1“线程的等待和唤醒”机制,实现两个线程,一个读取,一个写入的有序的情况!这里使用了while(true),无线死循环的情况,所以会一直不停的执行线程run()方法中的代码!
<span style="font-size:18px;"><span style="font-size:18px;">package com;
/**
* 注意点:
* <p/>
* 线程的等待和唤醒,必须是使用同一个”锁“对象的不同的线程,才能实现相互间的”等待和唤醒“。
* 必须使用”锁对象“.wait和”锁对象“.notify.显示指明,使用那个”锁对象“的线程”等待“或者”唤醒“.
* <p/>
* <p/>
* User: OF895
* Date: 2014/11/29
* Time: 16:01
*/
public class Res {
String name;
String sex;
boolean flag;
}
class Input implements Runnable {
private Res r;
public Input(Res r) {
this.r = r;
}
@Override
public void run() {
int x = 0;
while (true) {
synchronized (r) {
if (r.flag) {
try {
//如果flag为true的时候,也就是已经set了值的时候,那么就让这个“线程”wait下来
//程序在启动的时候,默认会有一个“线程池”,等待的线程都会存在于”线程池“中
r.wait(); //这里wait,必须指明是使用那个”锁“的线程
} catch (InterruptedException e) {
throw new RuntimeException("线程等待状态被打断了!");
}
}
if (x == 0) {
r.name = "mike";
r.sex = "man";
} else {
r.name = "丽丽";
r.sex = "女";
}
x = (x + 1) % 2;
//这个存放资源的类,在存放完资源后,需要将“标识置为true”,这样“取资源”的类,就可以去取了
//这里flag为true后,当前“线程”如果还拥有CPU的执行权,那么会再次进入这个run执行“同步代码块”中的代码,此时flag为true了
//那么当前的“线程”就“wait”了。
r.flag = true;
//在等待之前,将使用同一把“锁”对象的另一个线程,通知它启动!
r.notify();
}
}
}
}
class Output implements Runnable {
private Res r;
public Output(Res r) {
this.r = r;
}
@Override
public void run() {
while (true) {
synchronized (r) {
//当flag为false的时候,也就意味着Input尚未进行Set值的操作之前,让其wait
if (!r.flag) {
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(r.name + "....." + r.sex);
//程序执行到这里的时候,说明Res中的name和sex已经被打印了,”资源“被取走了,那么我们就置一下标识
r.flag = false;
//唤醒 这里notify,必须指明是使用那个”锁“的线程
r.notify();
}
}
}
}
class Start {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output output = new Output(r);
//通过这样的操作就实现了,Input线程执行完,"通知"Output线程去执行,这样就实现了他们之间有序的执行动作!
new Thread(in).start();
new Thread(output).start();
}
}
</span></span>
<span style="font-size:18px;">package com.ThreadDemo;
/**
* User: OF895
* Date: 2014/12/1
* Time: 13:24
*/
public class ProducerConsumerDemo {
public static void main(String[] args) {
ResourceDemo res = new ResourceDemo();
Producer producer = new Producer(res);
Consumer consumer = new Consumer(res);
Thread t1 = new Thread(producer);
Thread t3 = new Thread(producer);
Thread t2 = new Thread(consumer);
Thread t4 = new Thread(consumer);
t1.start();
t3.start();
t2.start();
t4.start();
}
}
class ResourceDemo {
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name) {
//这里需要使用while循环判断这个flag,因为如果只使用if(flag),那么它只会判断一次
//如果有多个“生产者”和多个“消费者”的情况下,那么就会出现“数据混乱”的情况,而不是生产一个,消费一个
<strong><span style="color:#ff0000;">while</span> </strong>(flag) {
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
this.name = name + "---" + count++;
System.out.println(Thread.currentThread().getName() + ".....生产者.." + this.name);
flag = true;
//这里需要使用notifyAll方法,将“线程池”中的所有的“生产者”和“消费者”的线程都唤醒,否则可能会出现如下情况:
//“生产线程”t1唤醒了"生产线程"t2,t3.....,但是却没有唤醒"消费线程",那么很有可能就解不了“锁”,出现了,全部线程wati的状态
//也就是所谓的“死锁”的情况
<span style="color:#ff0000;"><strong> this.notifyAll();</strong></span>
}
public synchronized void out() {
<span style="color:#ff0000;"> while </span>(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ".....消费者.." + this.name);
flag = false;
<strong><span style="color:#ff0000;"> this.notifyAll();</span></strong>
}
}
//生产者
class Producer implements Runnable {
private ResourceDemo res;
public Producer(ResourceDemo res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.set("商品");
}
}
}
//消费者
class Consumer implements Runnable {
ResourceDemo res;
public Consumer(ResourceDemo res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.out();
}
}
}</span>
3在jdk1.5之后,我们如何使用java.util.concurrent.locks.Lock对象替代synchronized关键字使用,以及它的新特性
<span style="font-size:18px;"> package com;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* User: OF895
* Date: 2014/12/1
* Time: 13:24
*
*
* 这个例子,才能达到有多个”生产者“和”消费者’线程的情况下
* 我们实现生产一个,消费一个的现象的出现
*/
public class ProducerConsumerDemo {
public static void main(String[] args) {
ResourceDemo res = new ResourceDemo();
Producer producer = new Producer(res);
Consumer consumer = new Consumer(res);
Thread t1 = new Thread(producer);
Thread t3 = new Thread(producer);
Thread t2 = new Thread(consumer);
Thread t4 = new Thread(consumer);
t1.start();
t3.start();
t2.start();
t4.start();
}
}
class ResourceDemo {
private String name;
private int count = 1;
private boolean flag = false;
//建立一个“锁”对象
private Lock lock = new ReentrantLock();
//通过lock对象的newCondition()方法我们可以获得一个“condition”实例
//通过这个condition我们可以获得wait,notify和notifyAll()方法
//Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
//所以我们使用这个lock对象这个新特性后,在“同一把锁”上面我们可以有多个condition对象
//所以我们可以做到“区别”await()和signal()
//这是jdk1.5之后的一个很重要的特性
<span style="color:#ff0000;"><strong> private Condition condition_produce = lock.newCondition();
private Condition condition_consummer = lock.newCondition();</strong></span>
public synchronized void set(String name) {
//这里的调用“锁”方法,就相当于原来的synchronized关键字,加上“锁”。
lock.lock();
try {
//这里需要使用while循环判断这个flag,因为如果只使用if(flag),那么它只会判断一次
//如果有多个“生产者”和多个“消费者”的情况下,那么就会出现“数据混乱”的情况,而不是生产一个,消费一个
while (flag) {
/**
* 这里为了区分“生成者”和“消费者”线程的等待和唤醒
* 避免下面使用condition.SingAll()方法将所有的线程,比如这里面“生产者”await()的情况下
* 执行完“生产的动作”后,我们只需要signAal()"消费者"线程就可以了,避免使用singAll()方法
* 所以我们使用这个lock对象这个新特性后,在“同一把锁”上面我们可以有多个condition对象
* 所以我们可以做到“区别”await()和signal()
*/
<span style="background-color: rgb(255, 0, 0);"> <strong>condition_produce.await();</strong></span>
}
this.name = name + "---" + count++;
System.out.println(Thread.currentThread().getName() + ".....生产者.." + this.name);
flag = true;
//这里需要使用notifyAll方法,将“线程池”中的所有的“生产者”和“消费者”的线程都唤醒,否则可能会出现如下情况:
//“生产线程”t1唤醒了"生产线程"t2,t3.....,但是却没有唤醒"消费线程",那么很有可能就解不了“锁”,出现了,全部线程wati的状态
//也就是所谓的“死锁”的情况
condition_consummer.signal();//这里就相当于原来的this.notify()方法,别单独封装成了对象和方法
} catch (Exception e) {
} finally {
//最后无论如何都要执行释放锁的操作
lock.unlock();
}
}
public void out() {
lock.lock();
try {
while (!flag) {
try {
/<span style="color:#ff0000;"><strong>/消费者线程等待
condition_consummer.wait();</strong></span>
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ".....消费者.." + this.name);
flag = false;
<span style="color:#ff0000;"><strong> //执行完“消费”任务后,可以使用特定的condition对象,唤醒"生产者"线程,这样就避免使用signAll()方法,也唤醒了“消费者‘线程了
condition_produce.signal();</strong></span>
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
//生产者
class Producer implements Runnable {
private ResourceDemo res;
public Producer(ResourceDemo res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.set("商品");
}
}
}
//消费者
class Consumer implements Runnable {
ResourceDemo res;
public Consumer(ResourceDemo res) {
this.res = res;
}
@Override
public void run() {
while (true) {
res.out();
}
}
}</span>
4线程的interrupt方法,可以让一个线程从“冻结"状态,重新获得执行权!解除冻结状态!
5线程的join方法:
<span style="font-size:18px;">package com.ThreadDemo;
/**
* 演示一下线程的join方法的使用
* User: OF895
* Date: 2014/12/1
* Time: 22:53
*/
public class JoinDemo {
public static void main(String[] args) throws Exception {
Demo d = new Demo();
Thread t1 = new Thread();
Thread t2 = new Thread();
t1.start();
t2.start();
/**
* 这个join方法的作用,当A线程执行到了B线程的join方法的时候,那么A线程会释放执行权,进入“冻结”状态
* 等待B线程执行完,A线程才会再次获得执行权,进行执行!
*
* 就比如这里因为t1.join()方法是在main(主线程)中“加入的”,所以这个代码执行的情况是:
* 当主线程遇到t1.join的时候,主线程进入冻结状态,因为前面t1.start,t2.start,开启了两个线程,所以此时有两个线程在执行状态
* 那么这两个线程交替执行,当t1执行完了的时候,主线程会再次获得执行权(主线程是不管t2线程是否执行完的),如果此时t2线程还没有执行结束
* 那么就会出现main线程和t2线程交替执行的状况!
*
*
* 所以join的作用:
* 就是可以在一个线程中,临时加入一个线程,执行线程中的代码!
*
*
*/
<span style="color:#ff0000;"> t1.join();</span>
for (int x = 0; x < 80; x++) {
System.out.println(Thread.currentThread().getName() + ".............." + x);
}
System.out.println("over!");
}
}
class Demo implements Runnable {
@Override
public void run() {
for (int x = 0; x <= 70; x++) {
System.out.println(Thread.currentThread().getName() + ".............." + x);
}
}
}
</span>
java线程池的概念:
<span style="font-size:18px;">package com.Thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* User: OF895
* Date: 14-9-18
* Time: 下午10:44
*/
public class ThreadPoolTest {
public static void main(String[] args) {
//创建一个可以动态添加“线程”的线程池
//ExecutorService threadPool = Executors.newCachedThreadPool();
//创建一个只有一个线程的线程池(这个也相当于单线程了,但是这个有个好处就是,每当这个线程“死掉”的时候,会动态生成一个新的线程,保证线程池中有一个线程)
//ExecutorService threadPool = Executors.newSingleThreadExecutor();
//创建一个有固定大小的“线程池”
ExecutorService threadPool = Executors.newFixedThreadPool(3);
//创建任务(这里的每一个Runnable,中的run()方法的代码块,就是要执行的任务),相当于提交10次任务给“线程池”去做处理。
for (int i = 1; i <= 10; i++) {
final int task = i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for(int j = 1; j <= 10; j++){
//循环10次,打印出当前线程的名字
System.out.println("线程" + Thread.currentThread().getName() + ",第" + j + "次循环。第" + task + "次任务中!");
}
}
});
}
System.out.println("10个任务都被提交了!");
//threadPool.shutdown(); 这个可以结束“线程池”中的线程。
}
}
</span>
带有“定时任务”的线程池:
<span style="font-size:18px;">package com.Thread;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* User: OF895
* Date: 14-9-19
* Time: 上午12:17
*/
public class ScheduleThreadPool {
public static void main(String[] args) {
//带有“定时任务”的线程池(默认创建3个线程),5秒后执行,每3秒执行一次定时任务。
Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":booming!");
}
},5,3, TimeUnit.SECONDS);
}
}
</span>
一个小例子:
<span style="font-size:18px;">package com.Thread;
/**
* 子线程循环10次,主线程循环100次。然后子线程循环10次,然后主线程循环100次。如此循环50次
* 这里需要采用“面向对象”的思维来分析代码。
* User: OF895
* Date: 14-9-15
* Time: 下午11:33
*/
public class TraditionalSynchronizedCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i < 50; i++){
//这里开启一个额外的线程调用子线程50次
business.sub(i);
}
}
}
).start();
//这里main方法也是一个线程,调用主线程50次,下面的synchronized关键字,确保了代码的互排斥
for(int i = 1 ; i < 50 ; i++){
business.main(i);
}
}
}
class Business {
public synchronized void sub(int i) {
for (int j = 1; j <= 10; j++) {
System.out.println("sub sequence :" + j + ", loop of" + i);
}
}
public synchronized void main(int i) {
for (int j = 1; j <= 100; j++) {
System.out.println("main sequence :" + j + ", loop of" + i);
}
}
}
</span>