第十三章 多线程 第三讲
来源:互联网 发布:约瑟夫环java简单实现 编辑:程序博客网 时间:2024/04/30 12:58
第十三章 多线程 第三讲
五 线程调度的方法详解
Sleep()方法是使当前线程睡眠指定的毫秒数,线程由进行状态进入不可运行状态,当指定的毫秒数过去后,如果有正在进行的线程,则进入就绪状态,如果没有正在进行的线程,则继续执行。释放CPU的执行权,不释放锁。
Yield()方法是使当前的线程暂停,将CPU资源让出来,运行其它的线程运行,此时,暂停的线程仍处于可运行的状态,不是阻塞状态,如果暂停后,没有要用的线程,则该线程继续执行。
Join()方法是当前线程阻塞,将CPU资源让出来,然后加入其它的线程,等加入的线程执行完了,再执行当前的线程。
Interrupt()方法只是为线程设置一个中断标记,并没有中断线程的运行。一个线程在被设置了中断标记之后仍可执行,isAlie()返回的 是true。实例方法interrupted()测试线程的中断标记,并不清除中断标记,而静态的interrupted()方法会测试当前执行的线程是否被中断,并且在肯定的情况下,清除当前线程对象的中断标记并返回。
Wait()方法是在程序进行中,如果用到synchronized,则是死锁,要解锁,要用到此方法,可以解除此锁,可使其它线程运行。但是并没有唤醒,要唤醒要用notify()方法。
释放CPU的执行权,释放锁。
Notify()唤醒调用wait()方法后被阻塞的线程。每次运行该方法只能唤醒一个线程。
notifyAll():唤醒所有调用wait()方法被阻塞的线程,这里的所有是由线程管理器决定的。
注:Sleep()和Wait()方法都是在释放资源,可是Sleep()是不释放锁,Wait()释放锁。
六 线程同步通信
生产者和消费者的问题是典型的多线程在遇到下标来不及改变时出现的异常,如果出现了此情况,可以用synchronized方法来锁定方法。使代 码该执行的执行完了在往下执行。在锁定之后,运行中,还可能会出现死锁的状态,解锁要用到wrie()方法和notify()方法,开释放锁定的资源,并 唤醒它。
在程序运行中,可能会出现一下方法,此时B为写入数据,A为取出数据:
(1)线程B写一次,线程A读一次
(2)在某个时候线程B运行速度比较快,在线程A未读取上一个数据之前,B就写了第二次数据,造成数据遗漏。
(3)在某个时候线程A运行速度比较快,它读完一次数据之后,线程B还没来得及写,线程又来读第二次。结果线程A读不到数据,导致运行出错。所以用到了一下方法:
private int index=0;//栈顶的位置
private char[] data=newchar[6];把压入的数据存放在数组里
public synchronized char pop(){
while(index==0){
try {
this.wait();//进入等待状态,并释放锁
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();//唤醒,使程序进行
index--;//取出后,栈顶的位置减1
System.out.println("custom:"+data[index]);
return data[index];
}
(4)线程B正在写数据时,线程A也来读取数据,这时可能线程B还没将数据写完,线程A将数据读走,导致程序出错。
//此方法是压入,想向堆栈中压入数据,数据类型是char类型的
public synchronized void push(charch){
while(index==data.length){
try {
this.wait();//进入等待状态,并释放锁
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
data[index]=ch;
index++;//压入数据之后,栈顶位置加1
System.out.println("produced:"+ch);
}
实例:
要用到4个类
此类是测试类
public class SyncTest {
public static void main(String[] args) {
// TODO Auto-generated methodstub
//s使临界资源
线程的开启
SyncStack s=new SyncStack();
Producer p=new Producer(s);//p生产者
Consumer c=new Consumer(s);//c消费者
Thread t1=new Thread(p);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
}
生产者的类,压入数据
class Producer implementsRunnable{
SyncStack stack;
public Producer(SyncStack stack) {
this.stack = stack;
}
@Override
public void run() {
// TODO Auto-generated methodstub
for(inti=0;i<20;i++){
charch=(char)(Math.random()*26+'A');//随机获取压入的数据
stack.push(ch);
try {
Thread.sleep((int)(Math.random()*300));
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
消费者的类,读出数据
class Consumer implementsRunnable{
SyncStack stack;
public Consumer(SyncStack stack) {
this.stack = stack;
}
@Override
public void run() {
// TODO Auto-generated methodstub
for(inti=0;i<20;i++){
char ch=stack.pop();
try {
Thread.sleep((int)(Math.random()*800));
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
临界资源的类,对压入和输出的调用
public class SyncStack {
private int index=0;
private char[] data=new char[6];
public synchronized void push(char ch){
while(index==data.length){
try {
this.wait();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
data[index]=ch;
index++;
System.out.println("produced:"+ch);
}
public synchronized char pop(){
while(index==0){
try {
this.wait();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.notify();
index--;
System.out.println("custom:"+data[index]);
return data[index]
}
锁的注意事项:
线程中锁定的不是方法,也不是对象,而是对临界资源的锁定
- 第十三章 多线程 第三讲
- 第十三章 多线程 第三讲
- 第十三章 多线程 第一讲
- 第十三章 多线程 第二讲
- 第十三章 多线程 第一讲
- 第十三章 多线程 第二讲
- 第13章多线程第三讲
- 第十三章 多线程
- 第十三章 多线程1
- 第十三章 1、多线程概念
- 技术博客:第十三章 多线程
- 第三讲
- 第三讲
- Java学习总结之第十三章 多线程
- java 第十三章 多线程(3)
- 第三章 多线程
- 多线程第三章(1)
- C++学习笔记【第三部分第十三章:拷贝控制】
- 五 打印流的应用 一------PrintStream
- 第十三章 多线程 第一讲
- 第十三章 多线程 第二讲
- 基础语法
- 文件操作
- 第十三章 多线程 第三讲
- 两种解析XML文档的方法---DOM和SAX
- MySQL 语句命令的使用
- Servlet的应用--Referer请求和参数传递
- 实现Session跟踪
- IO包中的其他对象
- MySQL 语句命令的使用 第二讲
- Application developer's guide
- cookie