首页 > 代码库 > Java多线程

Java多线程

一、停止线程(interrupt)

  停止线程意味着在线程处理玩任务之前停掉正在做的操作,Java之前的版本提供Thread.stop()方法,但这个方法是不安全的,已被废弃。

1、目前停止线程主要有两种方式:

  1)使用退出标志

  2)使用interrupt方法中断线程。此方式需要使用interrupt对要中断的线程进行标记,通过interrupted或isInterrupted方法结合相应逻辑(break等操作)实现线程中断。

2、interrupt、interrupted、isInterrupted区别

  1)interrupt标记线程为中断状态

  2)interrupted测试当前线程是否中断,并清除中断标记为false

  3)isInterrupted测试线程是否中断

3、使用interrupt方法中断线程实例

public class InterruptThread extends Thread {
    @Override
    public void run() {
        for(int i = 0; i < 50000; i++) {
            System.out.println("i = " + i);
            //if(this.isInterrupted()) {
            if(Thread.interrupted()) {
                System.out.println("thread stop");
                break;
            }
        }
    }
}
public class InterruptModel {
    public static void main(String[] args) {
        InterruptThread thread = new InterruptThread();
        thread.start();

        /*Thread.currentThread().interrupt();
        System.out.println("is stop 1 ? " + Thread.interrupted());
        System.out.println("is stop 2 ? " + Thread.interrupted());*/

        thread.interrupt();
        System.out.println("is stop 1 ? " + thread.isInterrupted());
        System.out.println("end");
    }
}

二、synchronize和volatile的区别

  这里需要注意的是synchronize取得的锁都是对象锁,而不是把一段代码或方法当做锁。也就是说当一个线程正在执行一个同步方法,那么其它线程要执行这个方法对应对象的其它同步方法也是不可以的(因为这个对象被第一个线程占用,这里是面试考试出题的地方,需要特别注意)。

  区别主要有一下4点

  1、volatile保证实例变量在多个线程间的可见性,不保证原子性;synchronized可以保证原子性及可见性

  2、volatile只能修饰变量;synchronized可以修饰方法及代码块

  3、volatile不会发生阻塞;synchronized会发生阻塞

  4、volatile解决多个线程间的可见性;synchronized解决多个线程间的同步性

public class Volatile extends Thread {
    volatile public static int count;

    synchronized private static void addCount() {
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println(count);
    }

    @Override
    public void run() {
        super.run();
        addCount();
    }
}
public class VolatileDemo {
    public static void main(String[] args) {
        Volatile[] volatiles = new Volatile[100];
        for (int i = 0; i < 100; i++) {
            volatiles[i] = new Volatile();
        }
        for (int i = 0; i < 100; i++) {
            volatiles[i].start();
        }
    }
}

三、线程间的通信

  Java提供了两种方式:1)通过wait/notify;2)通过管道方式(Java提供了PipedOutputStream、PipedInputStream、、PipedWriter、PipedReader四个类,刚兴趣的朋友可以自己搜索看看)

  1.wait和notify只能在同步方法或同步块中调用,否则抛出IllegalMonitorStateException异常

  2.用于线程间通信

  3.线程wait后必须有notify或notiAll唤醒,否则线程将永远等待下去

  4.wait可以使调用该方法的线程释放共享资源的锁

  5.notify可以随机唤醒等待队列中等待同一共享资源的一个线程

  6.notifyAll可以唤醒等待队列中等待同一共享资源的全部线程

  7.有参数wait可以自己到时唤醒,亦可以由别的线程唤醒

public class Wait extends Thread {
    private Object object;

    public Wait(Object object) {
        this.object = object;
    }

    @Override
    public void run() {
        synchronized (object) {
            try {
                System.out.println("start wait time : " + System.currentTimeMillis());
                object.wait();
                System.out.println("end wait time : " + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
public class Notify extends Thread {
    private Object object;

    public Notify(Object object) {
        this.object = object;
    }

    @Override
    public void run() {
        synchronized (object) {
            System.out.println("start notify time : " + System.currentTimeMillis());
            object.notify();
            System.out.println("end notify time : " + System.currentTimeMillis());
        }

    }
}
public class WaitAndNotifyModel {
    public static void main(String[] args) {
        Object object = new Object();
        Wait wait = new Wait(object);
        wait.start();
        Notify notify = new Notify(object);
        notify.start();
    }
}

四、yield和join的区别

  1、yield的作用是放弃当前的CPU资源让给其它线程去占用,但放弃的时间不确定,有可能刚放弃马上又获得CPU时间片

  2、Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程

 五、死锁

public class DeadLock implements Runnable {
    public String name;
    public Object object1 = new Object();
    public Object object2 = new Object();

    public void setName(String name) {
        this.name = name;
    }

    public void run() {
        if(name.equals("a")) {
            synchronized (object1) {
                System.out.println(name + " 获得 object1");
                System.out.println(name + " 等待 object2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (object2) {
                    System.out.println("1-->2");
                }
            }
        }
        if(name.equals("b")) {
            synchronized (object2) {
                System.out.println(name + " 获得 object2");
                System.out.println(name + " 等待 object1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (object1) {
                    System.out.println("2-->1");
                }
            }
        }
    }
}
public class DeadLockDemo {
    public static void main(String[] args) {
        DeadLock dt = new DeadLock();
        dt.setName("a");
        Thread t1 = new Thread(dt);
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        dt.setName("b");//同一DeadLock实例保证线程a、b竞争的共享资源为同一对象
        Thread t2 = new Thread(dt);
        t2.start();
    }
}

六、生产者消费者问题

  生产者生产产品到工厂,消费者从工厂取走产品,只有生产者提前生产出产品,消费者方能取走,当没有产品时,消费者等待,当生产者生产出产品通知消费者取产品。

工厂

public class Factory {
    public static int count = 0;
    Object object = new Object();

    public void pro() {
        synchronized (object) {
            while (count > 0) {
                try {
                    System.out.println("pro wait | " + Thread.currentThread().getName());
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count++;
            System.out.println("pro : " + count + " | " + Thread.currentThread().getName());
            object.notifyAll();
        }
    }

    public void cus() {
        synchronized (object) {
            while (count <= 0) {
                try {
                    System.out.println("cus wait | " + Thread.currentThread().getName());
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
                count--;
                System.out.println("cus : " + count + " | " + Thread.currentThread().getName());
            object.notifyAll();
        }
    }

}

生产者线程

public class ProducerThread extends Thread {
    private Factory f;

    public ProducerThread(Factory f) {
        this.f = f;
    }

    @Override
    public void run() {
        while (true)
            f.pro();
    }
}

消费者线程

public class CustomerThread extends Thread {
    private Factory f;

    public CustomerThread(Factory f) {
        this.f = f;
    }

    @Override
    public void run() {
        while (true)
            f.cus();
    }
}

运行实例

public class PCModel {
    public static void main(String[] args) {
        Factory f = new Factory();
        ProducerThread pt = new ProducerThread(f);
        CustomerThread ct1 = new CustomerThread(f);
        CustomerThread ct2 = new CustomerThread(f);
        pt.start();
        pt.setName("pt");
        ct1.start();
        ct1.setName("ct1");
        ct2.start();
        ct2.setName("ct2");
    }
}

 

Java多线程