Java并发编程基础

时间:2022-10-19 20:04:31

第一章 线程的操作

1.1创建多线程的方式

第一种:继承Thread

第二种:实现Runnable接口

1.2线程的常用方法

currentThread(): 获取当前线程

isAlive():判断当前线程是否处于活动状态

sleep():指定毫秒数让当前线程休眠。

getId():获取当前线程的Id

1.3停止线程

停止线程就是线程在处理任务完成之前,停掉正在进行的操作。Thread.stop()可以停止线程,但是最好不要用它,因为这个方法不安全,而且是过时的方法。

大多数停止一个线程操作使用Thread.interrupt().因为这个方法不会终止正在运行的程序,还需要加入一个判断才行。

Java有三种方法可以终止线程:

Ø  使用退出标志,使得线程正常退出,也就是当run方法完成后终止。

Ø  使用stop方法强行终止,坏处:使得一些清理工作等不到完成,而且会对锁定的对象进行解锁,导致数据得不到同步处理。

Ø  使用interrupt来终止,停止不了的线程:

Code Example:

public class MyThread extends Thread {

       @Override

       public void run() {

              super.run();

              for (int i = 0; i < 500000; i++) {

                     System.out.println("i=" +(i+1));

              }

       }

}

public class Run {

       public static void main(String[] args) {

              try {

                     MyThread thread = new MyThread();

                     thread.start();

                     Thread.sleep(2000);

                     thread.interrupt();

              } catch(InterruptedException e) {

                     System.out.println("maincatch");

                     e.printStackTrace();

              }

       }

}

从运行结果,interrupt并没有使得线程终止。那如何停止线层呢?

我们先了解如何判断一个线程是否终止:

this.interrupted():测试当前线程是否已经中断,当前线程是指运行this.

interrupted()方法线程。比如以上代码例子,调用的是thread.interrupt()

但是主线程并未中断,所以主线程是一直运行的。要让主线程终止,

Thread.currentThread.interrupt(). 另外,注意此方法自带清除功能第二次检测线程中断状态,就会返回false.

 

this.isInterrupted():测试线程是否已经中断,测试的是某一个线程对象是否已经中断,不会清除状态。

Java并发编程基础

异常终止:

如果在运行过程中抛出了异常,那么程序不会继续执行。

我们先考虑一种情况,break:

public class MyThread extends Thread {

       @Override

       public void run() {

              super.run();

              for (int i = 0; i < 500000; i++) {

                     if (this.isInterrupted()){

                            System.out.println("ThreadState: Interrupted");

                            break;

                     }

                     System.out.println("i=" +(i+1));

              }

              System.out.println("End!");

       }

}

输出结果:

Java并发编程基础

其实for循环后面的代码还需继续执行。

那我们抛出异常呢?

如果for循环和后面的代码都在try catch块里面,那么异常抛出后,后面代码就不会执行,如果for循环后面的代码放到了try catch块后面,那还是会执行的。

线程sleep时候中断线程,会进入catch块

public class MyThread extends Thread {

       @Override

       public void run() {

              super.run();

              try {

                     for (int i = 0; i < 500000; i++) {

                            Thread.sleep(200000);

                            System.out.println("i=" +(i+1));

                     }

                     System.out.println("End!");

              } catch(InterruptedException e) {

                     System.out.println("InterruptedException");

                     e.printStackTrace();

              }

       }

}

结果:

Java并发编程基础

使用return停止线程:

其实原因就是,一旦return,方法后面的代码不会执行。

public class MyThread extends Thread {

       @Override

       public void run() {

              super.run();

              for (int i = 0; i < 500000; i++) {

                     if (this.isInterrupted()){

                            System.out.println("ThreadState: Interrupted");

                            return;

                     }

                     System.out.println("i=" +(i+1));

              }

              System.out.println("End!");

       }

}
输出结果:

Java并发编程基础

之所以break之后,后面的代码还执行,是因为,break只是跳出for循环,并不影响后面的代码的执行。

1.4暂停线程

暂停线程意味着线程还可以继续恢复运行。使用suspend暂停或者挂起线程,使用resume恢复线程。

1.5yield

放弃当前CPU资源,将他让给其他线程去占用CPU时间,但是放弃的时间不确定,可能放弃了马上又获取了。

1.6线程的优先级

第二章 对象及其变量的并发访问

2.1synchronized 方法与对象

public class Data {

       public void print(){

              try {

                     System.out.println("Beginprint: ThreadName----"+Thread.currentThread().getName());

                     Thread.sleep(5000);

                     System.out.println("End!!");

              } catch(InterruptedException e) {

                     e.printStackTrace();

              }

       }

}

 

public class ThreadA implements Runnable{

       private Data data;

       public ThreadA(Data data) {

              this.data = data;

       }

       @Override

       public void run() {

              data.print();

       }

}

 

public class ThreadB implements Runnable{

       private Data data;

       public ThreadB(Data data) {

              this.data = data;

       }

       @Override

       public void run() {

              data.print();

       }

}

 

public class Run {

       public static void main(String[] args) {

              Data data = new Data();

              Thread a = new Thread(new ThreadA(data));

              a.setName("A");

              Thread b = new Thread(new ThreadB(data));

              b.setName("B");

              a.start();

              b.start();

       }

}

运行结果:

Java并发编程基础

如果我们在Data的方法上加上Synchronized.是什么效果呢?

Java并发编程基础

方法里面的内容顺序执行,但是线程A不一定先执行,这得看谁先拿到锁。

2.2脏读

赋值时是同步的,取值时没有同步,就有可能出现要读取的值被其他线程修改了。

解决方法:取值也同步。

2.3synchronized 锁重入

Synchronized拥有锁重入的功能,也就是在使用synchronized的时候,当一个线程得到了对象锁以后     ,并没有释放锁,当再次请求对象锁时,是可以再次得到的,比如synchronized方法 或者 块内部在调用本类其他方法或者同步块时,是永远可以得到锁的。

public class Data {

       public int d = 0;

       public synchronized void service1(){

              System.out.println("Service1");

              synchronized (this) {

                     d++;

                     synchronized (this) {

                            d=d*2;

                     }

              }

              service2();

       }

       public synchronized void service2(){

              System.out.println("Service2");

              service3();

       }

       public synchronized void service3(){

              System.out.println("Service3");

              System.out.println("value:"+d);

       }

}

2.4出现异常时,自动释放锁

当synchronized 方法内部或者块里面抛出异常,那么持有的锁会自动释放。

 

第三章 线程间的通信

3.1线程间不通信的代码示例

public class DataList {

       private List<String> list = newArrayList<String>();

       public void add(){

              list.add("nicky");

       }

       public int size(){

              return list.size();

       }

}

public class ThreadA implements Runnable{

       private DataList dataList;

      

       public ThreadA(DataList dataList) {

              this.dataList = dataList;

       }

       @Override

       public void run() {

              try {

                     for (int i = 0; i < 10; i++) {

                            dataList.add();

                            System.out.println("Add "+(i+1)+"elements");

                            Thread.sleep(1000);

                     }

              } catch (InterruptedExceptione) {

                     e.printStackTrace();

              }

       }

}

public class ThreadB implements Runnable{

       private DataList dataList;

      

       public ThreadB(DataList dataList) {

              this.dataList = dataList;

       }

       @Override

       public void run() {

              try {

                     while (true) {

                            if (dataList.size() == 5) {

                                   System.out.println("exit!!");

                                   throw newInterruptedException();

                            }

                     }

              } catch(InterruptedException e) {

                     e.printStackTrace();

              }

       }

}

public class Runner {

       public static void main(String[] args) {

              DataList list = new DataList();

              Thread t1 = new Thread(new ThreadA(list), "A");

              t1.start();

              Thread t2 = new Thread(new ThreadB(list), "B");

              t2.start();

       }

}

他们实现了通信,但是有一个弊端就是线程B不断的轮询,这样会浪费CPU资源。

3.2等待/通知机制

Ø  方法wait()的作用是当前的线程执行等待,然后就阻塞在这儿,直到有其他时间唤醒它。

Ø  Wait只能在同步方法或者同步块中被调用

Ø  执行wait,当前线程释放锁

Ø  如果调用wait没有获得锁,则抛出IllegalMonitorStateException,它是一个RuntimeException的子类。

Ø  方法notify也需要在同步方法或块中使用,即在调用前,也必须获得该对象的锁

Ø  如果没有持有适当的锁,则抛出IllegalMonitorStateException

Ø  如果有多个线程等待,线程规划器随便挑选一个,对其发出notify通知

Ø  Notify方法执行后,不会立即释放锁;Wait也不是立马就获得锁,

需要等到notify方法的线程执行完程序也就是退出同步块的时候才释放

Ø  当地一个被唤醒的线程执行完毕,它会释放锁,如果此时没有再次使用notify,即便该对象空闲,其他wait状态的线程由于没有得到通知,还需继续处于阻塞状态。

没有得到锁,调用wait抛出异常例子:

public class Run {

       public static void main(String[] args) {

              try {

                     String d = "nicky";

                     d.wait();

              } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              }

       }

}

Java并发编程基础

测试wait方法执行完后,自动释放锁,第二个线程可以进来,因为已经释放锁了。

public class DataList {

       private List<String> list = newArrayList<String>();

       public void add(){

              list.add("nicky");

       }

       public int size(){

              return list.size();

       }

      

       public void service(Object lock){

              try {

                     synchronized (lock) {

                            System.out.println("beginwait......");

                            lock.wait();

                            //Thread.sleep(40000);                           System.out.println("Endwait......");

                     }

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              }

       }

}

 

public class ThreadA implements Runnable{

       private Object lock;

      

       public ThreadA(Object  lock) {

              this.lock = lock;

       }

       @Override

       public void run() {

              System.out.println("Thread AExecuting");

              DataList datList = new DataList();

              datList.service(lock);

       }

}

 

public class ThreadB implements Runnable{

       private Object lock;

      

       public ThreadB(Object  lock) {

              this.lock = lock;

       }

       @Override

       public void run() {

              System.out.println("Thread BExecuting");

              DataList datList = new DataList();

              datList.service(lock);

       }

}

Java并发编程基础

如果上面的wait()改成Thread.sleep();执行结果:

Java并发编程基础

线程B并没有进来,因为sleep之后,一直阻塞,并没有释放锁。

结论:

同样是等待,但是wait会释放锁,sleep却不会释放锁。

在测试Notify释放锁:

public class DataList {

       private List<String> list = newArrayList<String>();

       public void add(){

              list.add("nicky");

       }

       public int size(){

              return list.size();

       }

      

       public void service(Object lock){

              try {

                     synchronized (lock) {

                            System.out.println("beginwait() ThreadName="+Thread.currentThread().getName());

                            lock.wait();

                            System.out.println("End wait()ThreadName="+Thread.currentThread().getName());

                     }

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              }

       }

      

       public void synNofify(Object lock){

              try {

                     synchronized (lock) {

                            System.out.println("beginnotify() ThreadName="+Thread.currentThread().getName()+"time="+

                                          System.currentTimeMillis());

                            lock.notify();

                            Thread.sleep(5000);

                            System.out.println("endnotify() ThreadName="+Thread.currentThread().getName()+"time="+

                                          System.currentTimeMillis());

                     }

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              }

       }

}

public class NotifyThreadA implements Runnable{

 

       private Object lock;

      

       public NotifyThreadA(Object lock) {

              this.lock = lock;

       }

 

       @Override

       public void run() {

              DataList dataList = new DataList();

              dataList.synNofify(lock);

       }

}

public class NotifyThreadB implements Runnable{

 

       private Object lock;

      

       public NotifyThreadB(Object lock) {

              this.lock = lock;

       }

 

       @Override

       public void run() {

              DataList dataList = new DataList();

              dataList.synNofify(lock);

       }

}

public class Runner {

       public static void main(String[] args) {

              Object lock = new Object();

              Thread t1 = new Thread(new ThreadA(lock), "A");

              t1.start();

              Thread nt1 = new Thread(new NotifyThreadA(lock),"NotifyThread A");

              nt1.start();

              Thread nt2 = new Thread(new NotifyThreadB(lock),"NotifyThread B");

              nt2.start();

       }

}

执行结果:

Java并发编程基础

我们可以分析出:

线程A调用wait方法之后,释放锁,Notify A线程进入调用notify之后,并没有立即释放,而是在同步代码块里的方法执行完毕,才释放锁,然后这个时候,线程A被唤醒,可能线程A继续,也可能是Notify ThreadB进入.

测试线程是wait状态,但此时调用了interrupt方法,则会出现Interrupt异常

public class Runner {

       public static void main(String[] args) {

              Object lock = new Object();

              Thread t1 = new Thread(new ThreadA(lock), "A");

              t1.start();

              t1.interrupt();

       }

}

Java并发编程基础

实验结论:

Ø  Wait方法被调用,会立即释放锁,然后该线程进入线程等待池

Ø  Norify方法被调用,则必须同步代码块或者让同步方法执行完毕,才会释放锁

Ø  同步代码块或者同步方法中,遇到异常,也会立即释放所

Ø  Sleep方法是阻塞方法,调用之后不会立即释放所

 

 

Notify方法只会唤醒一个线程:

Java并发编程基础

Java并发编程基础

NotifyAll唤醒所有的线程:

Java并发编程基础

执行结果:都被唤醒,并且执行

 Java并发编程基础

带有时间限制的wait(time)方法,在限定时间,看有没有线程唤醒他,如果没有,到时之后,自动唤醒;但不一定立即执行。

Java并发编程基础

Java并发编程基础

执行结果:

Java并发编程基础

到时之后,自动唤醒

3.3生产者与消费者模式

3.3.1一个生产者 一个消费者操作值

public class ValueObject {

       public static String value = "";

}

public class Producer {

       private String lock;

       public Producer(String lock) {

              super();

              this.lock = lock;

       }

       public void setValue(){

              try {

                     synchronized (lock) {

                            if (!ValueObject.value.equals("")) {

                                   lock.wait();

                            }

                            String value = System.currentTimeMillis()+"_"+System.nanoTime();

                            System.out.println("set valueis: "+value);

                            ValueObject.value = value;

                            lock.notify();

                     }

              } catch(InterruptedException e) {

                     e.printStackTrace();

              }

       }

}

public class Consumer {

       private String lock;

       public Consumer(String lock) {

              super();

              this.lock = lock;

       }

       public void getValue(){

              try {

                     synchronized (lock) {

                            if (ValueObject.value.equals("")) {

                                   lock.wait();

                            }

                            System.out.println("get valueis: " +ValueObject.value);

                            ValueObject.value = "";

                            lock.notify();

                     }

              } catch(InterruptedException e) {

                     e.printStackTrace();

              }

       }

}

public class ProduceThread implements Runnable{

       private Producer producer;

       public ProduceThread(Producer producer) {

              this.producer = producer;

       }

       @Override

       public void run() {

              for(;;){

                     producer.setValue();

              }

       }

}

public class ConsumeThread implements Runnable{

       private Consumer consumer;

       public ConsumeThread(Consumer consumer) {

              this.consumer = consumer;

       }

       @Override

       public void run() {

              for(;;){

                     consumer.getValue();

              }

       }

}

public class Runner {

       public static void main(String[] args) {

              String lock = new String("");

              Producer p = new Producer(lock);

              Consumer c = new Consumer(lock);

              Thread t1 = new Thread(new ProduceThread(p));

              Thread t2 = new Thread(new ConsumeThread(c));

              t1.start();

              t2.start();

       }

}

运行结果:

Java并发编程基础

3.3.2多生产与多消费 操作值假死

假死就是线程进入waiting状态,为什么呢,因为有可能你唤醒的是同类而不是异类,比如生产者有可能唤醒的是生产者,消费者有可能唤醒的是消费者

Java并发编程基础


Java并发编程基础



Java并发编程基础

怎么解决呢,很简单,将notify改为notifyAll,将异类全部唤醒。

Java并发编程基础

Java并发编程基础

3.4通过管道进行线程间通信

Java JDK提供了4个类来使得线程间可以通信:

PipedInputStream PipedOutputStream;

PipedReader PipedWriter

字节流

public class WriteData {

       public void write(PipedOutputStream out){

              try {

                     System.out.println("write:");

                     for (int i = 0; i < 300; i++) {

                            String outData = ""+(i+1);

                            out.write(outData.getBytes());

                            System.out.println(outData);

                     }

                     System.out.println();

                     out.close();

              } catch (IOException e) {

                     e.printStackTrace();

              }

       }

}

public class ReadData {

       public void read(PipedInputStream in){

              try {

                     System.out.println("read:");

                     byte[] bytes = new byte[20];

                     int len = in.read(bytes);

                     while(len != -1){

                            String newData = new String(bytes,0,len);

                            System.out.println(newData);

                            len = in.read(bytes);

                     }

                     System.out.println();

                     in.close();

              } catch (IOException e) {

                     e.printStackTrace();

              }

       }

}

public class ThreadWrite extends Thread {

       private WriteData write;

       private PipedOutputStream out;

       public ThreadWrite(WriteData write,PipedOutputStream out) {

              super();

              this.write = write;

              this.out = out;

       }

       @Override

       public void run() {

              write.write(out);

       }

}

public class ThreadRead extends Thread {

       private ReadData read;

       private PipedInputStream in;

       public ThreadRead(ReadData read, PipedInputStreamin) {

              this.read = read;

              this.in = in;

       }

       @Override

       public void run() {

              read.read(in);

       }

}

public class Runner {

       public static void main(String[] args) {

              WriteData write = new WriteData();

              ReadData read = new ReadData();

              PipedInputStream in = newPipedInputStream();

              PipedOutputStream out = newPipedOutputStream();

              try {

                     out.connect(in);

                     ThreadRead rt = new ThreadRead(readin);

                     rt.start();

                     Thread.sleep(2000);

                     ThreadWrite wt = new ThreadWrite(writeout);

                     wt.start();

              } catch (Exception e) {

                     e.printStackTrace();

              }

       }

}

交替执行:

public class DBTools {

       private volatile boolean exec = false;

       synchronized void backupA(){

              try {

                     while(exec){

                            wait();

                     }

                     for(int i = 0; i < 5; i++){

                            System.out.println("**********");

                     }

                     exec = true;

                     notifyAll();

              } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              }

       }

       synchronized void backupB(){

              try {

                     while(!exec){

                            wait();

                     }

                     for(int i = 0; i < 5; i++){

                            System.out.println("##########");

                     }

                     exec = false;

                     notifyAll();

              } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              }

       }

}

public class BackupA extends Thread{

       private DBTools tools;

       public BackupA(DBTools tools) {

              this.tools = tools;

       }

       @Override

       public void run() {

              tools.backupA();

       }

}

public class BackupB extends Thread{

       private DBTools tools;

       public BackupB(DBTools tools) {

              this.tools = tools;

       }

       @Override

       public void run() {

              tools.backupB();

       }

}

public class Runner {

       public static void main(String[] args) {

              DBTools tools = new DBTools();

              for(int i = 0; i < 20; i++){

                     new BackupA(tools).start();

                     new BackupB(tools).start();

              }

       }

}

运行结果:

Java并发编程基础

3.5join方法的使用

Join方法作用就是等待线程销毁

Java并发编程基础

一定是t1线程执行完毕,这个线程对象销毁才会执行主线程后面的代码。

在Join的时候,线程被中断,会抛出InterruptException异常

带有参数的join方法:如果join方法带有参数,那么到时间之后,如果运行join的线程还没有执行完毕,那么主线程就不必等了。

 

Sleep(long time) vs Join(long time):

都可以让线程等会儿,但是sleep是不会释放锁的,join默认采用的而是wait机制,所以是会释放锁的,那么其他线程话可以进入同步块或者同步方法继续执行。

 

第四章 Lock的使用

4.1简单的测试

Java并发编程基础

Java并发编程基础

Java并发编程基础


执行结果:

Java并发编程基础

public class Service2 {

       private Lock lock = new ReentrantLock();

       public void methodA(){

              try {

                     lock.lock();

                     System.out.println("Method Abegin Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());

                     Thread.sleep(5000);

                     System.out.println("Method Aend Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

       public void methodB(){

              try {

                     lock.lock();

                     System.out.println("Method Bbegin Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());

                     Thread.sleep(5000);

                     System.out.println("Method Bend Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

}

public class MyThreadAimplements Runnable {

       private Service2 service;

       public MyThreadA(Service2 service) {

              this.service = service;

       }

       @Override

       public void run() {

              service.methodA();

       }

}

public class MyThreadB implements Runnable {

       private Service2 service;

       public MyThreadB(Service2 service) {

              this.service = service;

       }

       @Override

       public void run() {

              service.methodB();

       }

}

public class MainExecute {

       public static void main(String[] args) {

              Service2 service2 = new Service2();

              Thread threadA = new Thread(new MyThreadA(service2));

              Thread threadB = new Thread(new MyThreadB(service2));

              threadA.start();

              threadB.start();

       }

}

运行结果:

Java并发编程基础

测试说明:

调用lock.lock()代码,就持有了对象监视器,其他线程只有等待锁被释放时再次争抢,效果和synchronized一样

4.2Condition实现等待、通知的错误用法和正确用法

Condition更加灵活,还可以实现选择性通知

错误用法

没有获取同步监视器:lock.lock()就调用Condition#await方法

这样会抛出异常:IllegalMonitorStateException

正确用法:

public class Service1 {

       private Lock lock = new ReentrantLock();

       public Condition condition = lock.newCondition();

       public void await(){

              try {

                     lock.lock();

                     System.out.println("await time= "+ System.currentTimeMillis());

                     condition.await();

              } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

       public void singal(){

              try {

                     lock.lock();

                     System.out.println("singaltime = "+ System.currentTimeMillis());

                     condition.signal();

              } finally{

                     lock.unlock();

              }

       }

}

public class MyThreadA implements Runnable {

       private Service1 service;

       public MyThreadA(Service1 service) {

              this.service = service;

       }

       @Override

       public void run() {

              service.await();

       }

}

public class MainExecute {

       public static void main(String[] argsthrows InterruptedException {

              Service1 service1 = new Service1();

              Thread threadA = new Thread(new MyThreadA(service1));

              threadA.start();

              Thread.sleep(3000);

              service1.singal();

       }

}

Java并发编程基础

4.3使用多个Condition实现通知部分线程

public class Service1 {

       private Lock lock = new ReentrantLock();

       public Condition conditionA = lock.newCondition();

       public Condition conditionB = lock.newCondition();

       public void awaitA(){

              try {

                     lock.lock();

                     System.out.println("Beginawait A, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());

                     conditionA.await();

                     System.out.println("Finishawait A, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());

              } catch (InterruptedExceptione) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

      

       public void awaitB(){

              try {

                     lock.lock();

                     System.out.println("Beginawait B, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());

                     conditionB.await();

                     System.out.println("Finishawait B, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

       public void singalAll_A(){

              try {

                     lock.lock();

                     System.out.println("singalAll_Athread name: "+Thread.currentThread().getName()+"time = "+ System.currentTimeMillis());

                     conditionA.signalAll();

              } finally{

                     lock.unlock();

              }

       }

       public void singalAll_B(){

              try {

                     lock.lock();

                     System.out.println("singalAll_Bthread name: "+Thread.currentThread().getName()+"time = "+ System.currentTimeMillis());

                     conditionB.signalAll();

              } finally{

                     lock.unlock();

              }

       }

}

public class MyThreadA implements Runnable {

       private Service1 service;

       public MyThreadA(Service1 service) {

              this.service = service;

       }

       @Override

       public void run() {

              service.awaitA();

       }

}

public class MyThreadB implements Runnable {

       private Service1 service;

       public MyThreadB(Service1 service) {

              this.service = service;

       }

       @Override

       public void run() {

              service.awaitB();

       }

}

public class MainExecute {

       public static void main(String[] argsthrows InterruptedException {

              Service1 service1 = new Service1();

              Thread threadA = new Thread(new MyThreadA(service1),"A");

              Thread threaB = new Thread(new MyThreadB(service1),"B");

              threadA.start();

              threaB.start();

              Thread.sleep(3000);

              service1.singalAll_A();

       }

}

测试结果:只会唤醒A线程

 

 Java并发编程基础

4.4生产者和消费者

4.4.1一对一

public class Service1 {

       private Lock lock = new ReentrantLock();

       public Condition condition = lock.newCondition();

       private boolean hasValue = false;

       public void set(){

              try {

                     lock.lock();

                     while (hasValue == true) {

                            condition.await();

                     }

                     System.out.println("##########");

                     hasValue = true;

                     condition.signal();

              } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

      

       public void get(){

              try {

                     lock.lock();

                     while (hasValue == false) {

                            condition.await();

                     }

                     System.out.println("**********");

                     hasValue = false;

                     condition.signal();

              } catch (InterruptedException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

}

public class MyThreadA implements Runnable {

       private Service1 service;

       public MyThreadA(Service1 service) {

              this.service = service;

       }

       @Override

       public void run() {

              for (int i = 0; i < 5; i++){

                     service.set();

              }

       }

}

public class MyThreadB implements Runnable {

       private Service1 service;

       public MyThreadB(Service1 service) {

              this.service = service;

       }

       @Override

       public void run() {

              for (int i = 0; i < 5; i++){

                     service.get();

              }

       }

}

public class MainExecute {

       public static void main(String[] argsthrows InterruptedException {

              Service1 service1 = new Service1();

              Thread threadA = new Thread(new MyThreadA(service1),"A");

              Thread threaB = new Thread(new MyThreadB(service1),"B");

              threadA.start();

              threaB.start();

       }

}

输出结果:

 Java并发编程基础

4.4.2多对多

先看容易假死的情况:

public class MainExecute {

       public static void main(String[] argsthrows InterruptedException {

              Service1 service1 = new Service1();

              Thread[] threadAList = new Thread[10];

              Thread[] threadBList = new Thread[10];

              Thread threadA = null;

              Thread threadB = null;

              for (int i = 0; i < 10; i++) {

                     threadA = new Thread(new MyThreadA(service1),"A"+(i+1));

                     threadB = new Thread(new MyThreadB(service1),"B"+(i+1));

                     threadAList[i] = threadA;

                     threadBList[i] = threadB;

              }

             

              for(int i = 0; i < 10; i++){

                     threadAList[i].start();

                     threadBList[i].start();

              }

       }

}

可能程序运行一会儿,还没有运行完,就不运行了,但是线程并没有结束,这就是假死造成的,唤醒的线程不正确,导致可能都在await

解决办法:

Singal 改成singalAll,每一次唤醒都是把对方的唤醒,让这些都唤醒的去抢锁,然后一个线程改变了值,剩余的唤醒线程就等待,直到再次他们被唤醒。

public class Service1 {

       private Lock lock = new ReentrantLock();

       public Condition condition = lock.newCondition();

       private boolean hasValue = false;

       public void set(){

              try {

                     lock.lock();

                     while (hasValue == true) {

                            condition.await();

                     }

                     System.out.println("##########");

                     hasValue = true;

                     condition.signalAll();

              } catch (InterruptedExceptione) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

      

       public void get(){

              try {

                     lock.lock();

                     while (hasValue == false) {

                            condition.await();

                     }

                     System.out.println("**********");

                     hasValue = false;

                     condition.signalAll();

              } catch(InterruptedException e) {

                     // TODO Auto-generatedcatch block

                     e.printStackTrace();

              } finally {

                     lock.unlock();

              }

       }

}

4.5公平锁与非公平锁

所谓公不公平,其实就是按照是不是先来先获取锁,非公平的是随机的获取锁,而公平的是按照先来先获取锁。

在构造lock的时候,加一个boolean值,如果为true,表示是公平锁。

4.6一些常用方法

GetHoldCount:查询当前线程保持此锁的个数,也就是调用lock方法的次数

GetQueueLength:返回正在等待获取锁的线程估计数

GetWaitQueueLength(Condition condition):返回等待与此锁定相关给定条件Condition线程估计数,比如有5线程,每一个线程都执行了同一个condition对象的await方法,则返回值是5.

HasQueuedThread(Thread thread):查询此线程是否正在等待获取此锁

HasQueuedThreads():查询是否有线程正在等待获取此锁

hasWiaters(Condition condition):查询是否有线程是否正在等待与此锁有关的condition

isFair:判断是不是公平锁

isHeldByCurrentThread:查询当前线程是否保持此锁

isLocked:查询此锁是否由任意线程保持

lockInterruptibly:如果当前线程未被中断,获取此锁,如果已被中断,则抛出异常

tryLock:尝试获取锁,如果获取成功,标记下该线程获取到了锁,然后返回ture,如果没有直接给返回false.

tryLock(long timeout,TimeUnit unit):在给定时间范围内吗,去尝试获取锁,如果获取成功,标记下该线程获取到了锁,然后返回ture,如果没有直接给返回false.如果超时,则不会去尝试获取锁了。

await():让线程进入等待通知状态,在未接受到通知之前,可通过中断结束等待状态,并抛出异常

awaitUninterruptibly: 让线程进入等通知待状态,无法被中断

awaitNanos:若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,则返回0或负数。

 

awaitUntil: 适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的某一时刻。

 

4.7ReentrantReadWriteLock读写锁

特点:读读共享;写写互斥;读写互斥;写读互斥

读读共享:

Java并发编程基础

如果读读共享,说明只要是读,应该都可以进去,而不是一个线程独占锁,另外一个读线程需要等到

Java并发编程基础

Java并发编程基础

Java并发编程基础

运行结果:
Java并发编程基础

几乎同一时间进入,第二个线程并没有等待10s

写写互斥:

Java并发编程基础

运行结果是第一个线程执行完了,第二个线程才能获取所进来

同样读写是一样的,如果你读的时候,写的线程进不来;写的时候,也不能读

 

 

第五章 定时器Timer

5.1schedule方法测试

指定日期执行某一任务:

Java并发编程基础

5.2方法schedule(TimeTask task,Date firstTime,long period):

指定日期后,按指定的时间间隔无线循环执行某一任务

public class TimerTest {

       private static Timer timer = new Timer();

       static public class MyTask extendsTimerTask{

 

              @Override

              public void run() {

                     System.out.println("Running!Time is: "+new Date());

              }

       }

      

       public static void main(String[] args) {

              try {

                     MyTask task = new MyTask();

                     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                     String dateString = "2016-10-1114:26:00";

                     Date dateRef = sdf.parse(dateString);

                     System.out.println("字符串时间:"+dateRef.toLocaleString()+当前时间: "+newDate().toLocaleString());

                     timer.schedule(taskdateRef, 2000);

              } catch(ParseException e) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

              }

       }

}

输出结果:

Java并发编程基础

指定时间后,每隔2000ms执行一次任务。

5.3schedule(TimeTask task, long delays)

在当前时间为基础,延迟delys毫秒后执行任务:

Java并发编程基础

5.4schedule(TimeTask task,long delays,long period)

当前时间为基准,延迟delys毫秒后,然后以perid为时间间隔无限循环执行此任务