多线程循环交替输出1-100【extends Thread】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/J080624/article/details/53002559

实践目标:使用两个线程打印 1-100. 线程1, 线程2 交替打印

其实就是多线程之间的线程通信,使用wait、notify或者notifyAll。

如下的三个关键字使用的话,都得在同步代码块或同步方法中。

① wait():一旦一个线程执行到wait(),就释放当前的锁。

② notify()唤醒wait的一个的线程;

③ notifyAll():唤醒所有线程;


示例代码如下:

class PrintNum extends Thread {
    static int num = 1;
    // 静态成员变量,保证锁的唯一
    static Object obj = new Object();
    public void run() {
        while (true) {
            //obj can instead of PrintNum.class
            synchronized (obj) {
                /*当前线程活动期间才能唤醒其他等待线程*/
                obj.notify();
                if (num <= 100) {
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":"
                            + num);
                    num++;
                } else {
                    break;
                }

                try {
                    obj.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

}

public class TestCommunication {
    public static void main(String[] args) {
        Thread t1 = new PrintNum();
        Thread t2 = new PrintNum();

        t1.setName("thread1");
        t2.setName("thread2");
        t1.setPriority(Thread.MAX_PRIORITY);//10
        t2.setPriority(Thread.MIN_PRIORITY);//1

        t1.start();
        t2.start();
    }
}

调用start()方法,它 会新建一个线程然后执行run()方法中的代码。但是并不意味着多次调用t1.start()会创建多个线程并执行run()方法!Thread执行了start之后不可以再次执行start!

那么为什么不直接调用run()方法呢?

如果直接调用run()方法,并不会创建新线程,方法中的代码会在当前调用者的线程中执行。


另外查看Thread会发现,Thread实现了Runnable接口,实现了run方法并自定义了一系列方法。

故而使用实现Runnable并重写run方法也可以:多线程实现Runnable接口


锁的唯一性

这里使用的锁如下:

static Object obj = new Object();

在Main方法里面我们创建了两个PrintNum对象,那么是不是有两个Object obj = new Object();?这样岂不是不能保证线程安全,同步失败?

这里就要掌握类的加载及类中成员变量的加载。

实例化对象的执行顺序

如果类还没有被加载:

1、先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。
2、执行子类的静态代码块和静态变量初始化。
3、执行父类的实例变量初始化(例如:int a;初始化就是0,引用类型就是null)
4、执行父类的构造函数
5、执行子类的实例变量初始化(例如:int a;初始化就是0,引用类型就是null)
6、执行子类的构造函数 。

如果类已经被加载:

则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。

即 虽然创建了两个PrintNum对象,但是静态成员变量obj只有一个!这就保证了同步控制。

基于锁的唯一性,那么我们可以使用PrintNum.class来代理obj作为锁进行同步控制。

阅读更多

扫码向博主提问

流烟默

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • Java
  • 数据库
  • Linux
  • HTML5
去开通我的Chat快问
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页