jdk线程的简单使用

摘要:
publicclassThreadDemo01{publicstaticvoidmain(String[]args){Thread1thread1=newThread1(“thread1”);}}}}classThread2扩展线程{publicThread2(Stringname){super(name);i<

一、线程的实现方式
方式一:继承Thread类
一个类只要继承了Thread类,并重写run()方法,则就可以实现多线程的操作。

public class ThreadDemo01 {

    public static void main(String[] args) {
        Thread1 thread1 = new Thread1("thread1");
        Thread2 thread2 = new Thread2("thread2");

        System.out.println(thread1.getName());
        System.out.println(thread2.getName());

        thread1.start();//启动线程
        thread2.start();
    }
}

class Thread1 extends Thread {
    public Thread1(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Thread1 : " + i);
        }
    }
}

class Thread2 extends Thread {
    public Thread2(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Thread2 : " + i);
        }
    }
}

方式二:实现Runnable接口
一个类只要实现了Runnable类,并重写run()方法,则就可以实现多线程的操作。

public class ThreadDemo03 {

    public static void main(String[] args) {
        Thread thread1 = new Thread(new MyThread1(), "thread1");
        Thread thread2 = new Thread(new MyThread2(), "thread2");

        System.out.println(thread1.getName());
        System.out.println(thread2.getName());

        thread1.start();//启动线程
        thread2.start();
    }
}

class MyThread1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("MyThread1 :" + i);
        }
    }
}

class MyThread2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("MyThread2 :" + i);
        }
    }
}

两种启动方式的比较

将我们希望线程执行的代码放到run方法中,然后通过start方法来启动线程,start方法首先为线程的执行准备好系统资源,然后再去调用run方法

两种方法均需执行线程的start方法为线程分配必须的系统资源,调度线程运行并执行线程的run方法;在使用的时候使用实现接口优先(避免单继承);实现Runnable接口的方式能够实现资源的共享。

二、Thread的JDK源码分析

Thread thread1 = new Thread(new MyThread1(), "thread1");

Thread 构造方法源码如下:

public Thread(String name) {
    init(null, null, name, 0);
}

public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

public Thread(Runnable target, String name) {
    init(null, target, name, 0);
}
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
  …..
       this.name = name.toCharArray();
       this.target = target;
  …..
}
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}
public void run() {
    if (target != null) {
        target.run();
    }
}

1)当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number,该number将是自动增加的,并被所有的Thread对象所共享(因为它是static的成员变量);

2)当使用继承Thread类来生成线程对象时,我们需要重写run()方法,因为Thread类的run()方法此时什么事情都没做(target==null);

3)当使用实现Runnable接口来生成线程对象时,我们需要实现Runnable接口的run()方法,然后使用new Thread(new MyThread())(假使MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run()方法就会调用MyThread类的run方法,这样我们自己编写的run()方法就执行了。

三、线程中成员变量和局部变量的使用

1)如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,他们对该成员变量是彼此影响的(也就是说一个线程对成员变量的改变会影响到另一个线程)。

public class ThreadDemo04 {
    public static void main(String[] args) {
        HelloThread r = new HelloThread();
        Thread thread1 = new Thread(r);
        Thread thread2 = new Thread(r);

        thread1.start();
        thread2.start();
    }
}

class HelloThread implements Runnable {
    int i; //成员变量

    @Override
    public void run() {
        while (true) {
            System.out.println("number: " + this.i++);

            try {
                Thread.sleep((long) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (10 == this.i) {
                break;
            }
        }
    }
}

结果是:

number: 0
number: 1
number: 2
number: 3
number: 4
number: 5
number: 6
number: 7
number: 8
number: 9

2)如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝,一个线程对该局部变量的改变不会影响到其他的线程。

public class ThreadDemo05 {
    public static void main(String[] args) {
        WorldThread r = new WorldThread();
        Thread thread1 = new Thread(r);
        Thread thread2 = new Thread(r);

        thread1.start();
        thread2.start();
    }
}

class WorldThread implements Runnable {

    @Override
    public void run() {
        int i = 0;
        while (true) {
            System.out.println("number: " + i++);

            try {
                Thread.sleep((long) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (10 == i) {
                break;
            }
        }
    }
}

结果是:

number: 0
number: 0
number: 1
number: 1
……

四、卖票示例

50张票,3个窗口买,每个窗口相当于一个线程。

使用继承Thread类的方式卖票:

class MyThread1 extends Thread {
    private Integer num = 50;
    public MyThread1(String name) {
        super(name);
    }
    public void run() {
        int count = 0;
        for (int i = 1; i <= 200; i++) {
            if(num > 0){
                count ++;
                System.out.println(getName() + "卖出第--->" + num-- +"张票");
            }
        }
        System.err.println(getName()+"卖了"+ count +"张票" );
    }
}

getName()方法来自于Thread类中,故可以直接获得。

使用实现Runnable的方式卖票:

class MyThread2 implements Runnable{
    private Integer num = 50;
    public void run() {
        int count = 0;
        for (int i = 0; i < 200 ; i++) {
            if(num > 0){
                count ++;
                System.out.println(Thread.currentThread().getName()
                                + "卖出第--->" + num-- +"张票");
            }
        }
    System.err.println(Thread.currentThread().getName()
         +  "卖了"+ count +"张票" );
    }
}

由于该类实现了Runnable接口,该接口中并没有获取线程方法名称的方法,故只能采用Thread.currentThread().getName()这种最通用的方法来获得正在执行的线程名称。

两种卖票方式的比较:

继承方式:资源不能共享;一共卖出去150张票,每个窗口各50张;由于继承了Thread类之后就不能再继承其他类了;

接口方式:资源共享;一共卖出去50张票;方便以后扩展。

免责声明:文章转载自《jdk线程的简单使用》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java安全之安全加密算法国威电话机WS824(5D)-3型调试下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

SqlServer Alwayson 搭建排错记录(二)

  下面记录下建立好alwayson可用性组后,向可用性组内添加数据库出现过的问题及解决方法 一、数据库未处于恢复状态   将数据库联接到可用性组的时候报错: 数据库“XXXX”未处于恢复状态,而此状态是镜像数据库或辅助数据库所必需的。必须使用 WITH NORECOVERY 还原远程数据库。 (Microsoft SQL Server,错误: 1464)...

Netty (1)

目录 Netty(1) 传统的阻塞I/O模型(BIO) 特点 问题 事件驱动模型 Netty高效的 Reactor 线程模型 Reactor单线程模型 Reactor多线程模型 Reactor主从多线程模型 Netty特性 多路复用模型 数据零拷贝 无锁化设计 高性能的序列化框架 Netty(1) 官网的介绍,Netty 是...

TableView的使用

            项目现在基本出了一个版本,虽然做的是边缘工作,但是用到的东西还是整理一下吧,毕竟也算学了一点点东西。首先是TableView的使用。RWT是SWT的子集,因此,RWT中可能没有完全实现SWT的全部接口,也没有SWT那么完善。两者的架构不同,表现在显示形式,界面也不尽相同,但是基本的控件的时候还是相同的。这里首先通过SWT来学习一些常...

C#跨线程修改控件——从MSIL和汇编看Invoke, 多线程, 事件与事件委托

相信大家刚开始写winform的时候都遇到过这样的问题,当跨线程修改控件属性时会遇到如下的异常: 线程间操作无效: 从不是创建控件"progressBar1"的线程访问它。 这是相应的产生上述异常的代码: 1 #region Auto-Generated Properties 2 3 // DelegateDemo - Director.cs...

Java 多线程加锁的方式总结及对比(转载)

转自https://blog.csdn.net/u010842515/article/details/67634813 参考博文:http://www.cnblogs.com/handsomeye/p/5999362.html 一.Java多线程可以通过: 1. synchronized关键字 2. Java.util.concurrent包中的lock接...

php imagemagick 处理 图片剪切、压缩、合并、插入文本、背景色透明

php有一款插件叫做imagemagick,功能很强大,提供了图片的很多操作,图片剪切、压缩、合并、插入文本、背景色透明等。并且有api方法调用和命令行操作两种方式,如果只是简单处理的话建议api方法调用,如果是很复杂的操作建议服务器端搭shell命令行操作,因为api方法调用同操作对比命令行他更吃内存,并且效率没有命令行那么高。 本文章就对于这些常见操作...