线程相关

线程的3种方式

java1.5 以后java.util.concurrent包, 在并发编程中很常用的实用工具类。

class MyThread2 implements Runnable{

    @Override
    public void run() {
        System.out.println("implements Runable...");
    }
}

class MyThread extends Thread{s    
    @Override
    public void run() {
        System.out.println("extends Thread...");
    }
}

class MyThread3 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("implements callable...");
        return 200;
    }    
}


public class ThreadDemo {

    public static void main(String[] args) {
        new MyThread().start();
        new Thread(new MyThread2()).start();
        FutureTask task = new FutureTask<>(new MyThread3());
        new Thread(task).start();
    }
}
//输出
extends Thread...
implements Runable...
implements callable...

线程的小题目

题目:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1, 实现交替,来5轮,变量初始值为零。


/**
 * 线程实现:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1,
 *    实现交替,来5轮,变量初始值为零
 * 
 * @author dudy
 */

class ShareData {
    private int count = 0;

    public synchronized void increment() throws Exception {
        while (this.count != 0) {
            this.wait();
        }
        ++count;
        System.out.println(Thread.currentThread().getName() + "--> " + count);
        this.notify();
    }

    public synchronized void decrement() throws Exception {
        while (this.count == 0) {
            this.wait();
        }
        --count;
        System.out.println(Thread.currentThread().getName() + "--> " + count);
        this.notify();
    }
}

public class ThreadDemo02 {

    public static void main(String[] args) {

        final ShareData data = new ShareData();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 5; i++) {

                    try {
                        data.increment();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "AA").start();


        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 10; i++) {

                    try {
                        data.decrement();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "BB").start();


        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 10; i++) {

                    try {
                        Thread.sleep(200);
                        data.increment();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "CC").start();


        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 5; i++) {

                    try {
                        Thread.sleep(500);
                        data.decrement();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "DD").start();
    }

}

注意: 当我们在判断等待条件的时候要用while 在 API中 wait()这样写道: 在没有被通知、中断或超时的情况下,线程还可以唤醒一个所谓的虚假唤醒 (spurious wakeup)。虽然这种情况在实践中很少发生,但是应用程序必须通过以下方式防止其发生,即对应该导致该线程被提醒的条件进行测试,如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中,如下面的示例:

synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
     }

synchronized代码块锁


class Phone
{
    public static synchronized void getIOS() throws InterruptedException
    {
        Thread.sleep(5000);
        System.out.println("------getIOS");
    }
    public synchronized void getAndroid() throws InterruptedException
    {
        System.out.println("------getAndroid");
    }    

    public void helloPhone() throws InterruptedException
    {
        System.out.println("------helloPhone");        
    }
}

public class ThreadDemo3
{
    public static void main(String[] args)
    {
        final Phone phone = new Phone();
        final Phone phone2 = new Phone();

        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    phone.getIOS();
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        },"AA").start();

        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    //phone.getAndroid();
                    //phone.helloPhone();
                    phone2.getAndroid();
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        },"BB").start();        

    }
}
//1    首次执行,苹果还是android?
//2 新增Thread.sleep试试,苹果还是android?
//3 新增普通方法试试,苹果还是hello?
//4 新增第2部手机试试,苹果还是android?
//5 换成静态同步方法,同一部手机,苹果还是android?
//6 换成静态同步方法,2部手机,苹果还是android?
//7 一个静态同步方法,另一个非静态同步方法,同一部手机,苹果还是android?
//8 一个静态同步方法,另一个非静态同步方法,2部手机,苹果还是android?

note:

  • 一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其他的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
  • 锁的是当前对象this,被锁定后,其他的线程都不能进入到当前对象的其他synchronized方法
  • 加个普通方法后发现和同步锁无关
  • 换成两个对象后,不是同一把锁了,情况立刻变化
  • 都换成静态同步方法后,情况又变化
  • 所有的非静态同步方法用的都是同一把锁--实例对象本身
  • 所有的静态同步方法用的也是同一把锁--类对象本身