您的位置:首页 > 编程语言 > Java开发

[零基础学JAVA]Java SE应用部分-26.多线程(04) 推荐

2009-02-19 20:25 946 查看
生产者和消费者问题(1)



生产者和消费者问题(2)




class Person{
String name = "张三";
String sex = "男";
// 张三 --> 男
// 李四 --> 女
}
class Pro implements Runnable{
//声明一个共享区域
Person per = null;
public Pro(Person p){
this.per = p;
}
public void run(){
int i = 0;
while(true){
if (i==0){
per.name = "李四";
per.sex = "女";
i=1;
}else{
per.name = "张三";
per.sex = "男";
i =0;
}
}
}
}
class Cus implements Runnable{
Person per = null;
public Cus(Person p){
this.per = p;
}
public void run(){
while(true){
System.out.println(per.name+" --> "+per.sex);
}
}
}
public class ThreadDemo01{
public static void main(String args[]){
Person per = new Person();
Pro p = new Pro(per);
Cus c = new Cus(per);
new Thread(p).start();
new Thread(c).start();
}
}
看下效果:



以上代码已经可以从输出中看见了一些错误了,所以此处我们可以将代码进行修改,加入一些延迟,这样错误比较明显了

class Person{
String name = "张三";
String sex = "男";
// 张三 --> 男
// 李四 --> 女
}
class Pro implements Runnable{
//声明一个共享区域
Person per = null;
public Pro(Person p){
this.per = p;
}
public void run(){
int i = 0;
while(true){
if (i==0){
per.name = "李四";
try{
Thread.sleep(100);
}catch (Exception e){}
per.sex = "女";
i=1;
}else{
per.name = "张三";
per.sex = "男";
i =0;
}
}
}
}
class Cus implements Runnable{
Person per = null;
public Cus(Person p){
this.per = p;
}
public void run(){
while(true){
try{
Thread.sleep(100);
}catch (Exception e){}
System.out.println(per.name+" --> "+per.sex);
}
}
}
public class ThreadDemo02{
public static void main(String args[]){
Person per = new Person();
Pro p = new Pro(per);
Cus c = new Cus(per);
new Thread(p).start();
new Thread(c).start();
}
}



之前的两个问题已经全部出现了,现在解决第一个:关于设置内容的问题;
· 永远要保持张三是男,李四是女。

class Person{
private String name = "张三";
private String sex = "男";
// 张三 --> 男
// 李四 --> 女
public synchronized void set(String name,String sex){
this.name = name;
// 加入延迟验证设置是否生效
try{
Thread.sleep(100);
}catch (Exception e){}
this.sex = sex;
}
//设置一个输出方法
public synchronized void get(){
try{
Thread.sleep(100);
}catch (Exception e){}
System.out.println(this.name+" --> "+this.sex);
}
}
class Pro implements Runnable{
//声明一个共享区域
Person per = null;
public Pro(Person p){
this.per = p;
}
public void run(){
int i = 0;
while(true){
if (i==0){
per.set("李四","女");
i=1;
}else{
per.set("张三","男");
i =0;
}
}
}
}
class Cus implements Runnable{
Person per = null;
public Cus(Person p){
this.per = p;
}
public void run(){
while(true){
per.get();
}
}
}
public class ThreadDemo03{
public static void main(String args[]){
Person per = new Person();
Pro p = new Pro(per);
Cus c = new Cus(per);
new Thread(p).start();
new Thread(c).start();
}
}



通过同步方法,确实解决了设置上的问题,张三是男的,李四是女的,但是第二个问题还没有解决,以上效果看到得只是假像,如果休眠时间设置都取消的话可以看出问题哈~

class Person{
private String name = "张三";
private String sex = "男";
// 张三 --> 男
// 李四 --> 女
public synchronized void set(String name,String sex){
this.name = name;
// 加入延迟验证设置是否生效
this.sex = sex;
}
//设置一个输出方法
public synchronized void get(){
System.out.println(this.name+" --> "+this.sex);
}
}
class Pro implements Runnable{
//声明一个共享区域
Person per = null;
public Pro(Person p){
this.per = p;
}
public void run(){
int i = 0;
while(true){
if (i==0){
per.set("李四","女");
i=1;
}else{
per.set("张三","男");
i =0;
}
}
}
}
class Cus implements Runnable{
Person per = null;
public Cus(Person p){
this.per = p;
}
public void run(){
while(true){
per.get();
}
}
}
public class ThreadDemo04{
public static void main(String args[]){
Person per = new Person();
Pro p = new Pro(per);
Cus c = new Cus(per);
new Thread(p).start();
new Thread(c).start();
}
}



如果设置成只有一个休眠中断的话看得明显

class Person{
private String name = "张三";
private String sex = "男";
// 张三 --> 男
// 李四 --> 女
public synchronized void set(String name,String sex){
this.name = name;
// 加入延迟验证设置是否生效
this.sex = sex;
}
//设置一个输出方法
public synchronized void get(){
System.out.println(this.name+" --> "+this.sex);
}
}
class Pro implements Runnable{
//声明一个共享区域
Person per = null;
public Pro(Person p){
this.per = p;
}
public void run(){
int i = 0;
while(true){
if (i==0){
per.set("李四","女");
i=1;
}else{
per.set("张三","男");
i =0;
}
}
}
}
class Cus implements Runnable{
Person per = null;
public Cus(Person p){
this.per = p;
}
public void run(){
while(true){
try
{
Thread.sleep(500);
}
catch (Exception e)
{
}
per.get();
}
}
}
public class ThreadDemo04{
public static void main(String args[]){
Person per = new Person();
Pro p = new Pro(per);
Cus c = new Cus(per);
new Thread(p).start();
new Thread(c).start();
}
}



如果不让其重复取值,我们可以学习下下面的知识
绿灯可以放数据,不能取数据



红灯可以取数据,不能放数据



同理依次执行哈~



如果红灯时,即消费者(read)取数据时,CPU将资源给了生产者,当生产者将数据要放入时,发现是红灯,只能等待哈~



等到绿灯时生产者才能将cccc数据放入哈~



这样的机制就是线程的等待和唤醒,也就是下面的内容哈~
线程的等待及唤醒



当发现消费者没有取走内容的时候,生产者应该等待
当消费者把内容取走之后,生产者才可以放。

class Person{
private String name = "张三";
private String sex = "男";
private boolean flag = false;
// flag = true时表示允许生产但不允许取走
// flag = false时表示允许取走但不允许生产
// 张三 --> 男
// 李四 --> 女
//编写一个设置内容的方法
public synchronized void set(String name,String sex){
//如果flag的值不是true则要等待
if (!flag){
//等待
try{
wait();
}catch(Exception e){}
}
try{
Thread.sleep(100);
}catch (Exception e){}
// 如果向下继续执行了,则表示可以设置,flag = true
this.name = name;
this.sex = sex;
// 修改设置的标志
flag = false;
//唤醒其他线程
notify();
}
//设置一个输出方法
public synchronized void get(){
// 如果flag的值为true的时候,表示要等待
if(flag){
try{
wait();
}catch(Exception e){}
}
try{
Thread.sleep(100);
}catch (Exception e){}
//如果向下执行了,则表示允许取出
System.out.println(this.name+" --> "+this.sex);
//改变标志,表示可以生产了
flag = true;
notify();
}
}
class Pro implements Runnable{
//声明一个共享区域
Person per = null;
public Pro(Person p){
this.per = p;
}
public void run(){
int i = 0;
while(true){
if (i==0){
per.set("李四","女");
i=1;
}else{
per.set("张三","男");
i =0;
}
}
}
}
class Cus implements Runnable{
Person per = null;
public Cus(Person p){
this.per = p;
}
public void run(){
while(true){
per.get();
}
}
}
public class ThreadDemo05{
public static void main(String args[]){
Person per = new Person();
Pro p = new Pro(per);
Cus c = new Cus(per);
new Thread(p).start();
new Thread(c).start();
}
}

看下效果:这样就解决了第二个问题



以上的三个方法,实际上是Object类中的三个方法。



控制线程的生命周期






以上的很多方法都不建议继续使用了,因为会造成死锁,那么如果我现在要停止一个线程的运行,该怎么办?
C盘拷贝内容到D盘,中止拷贝时系统会有些延迟,同理我们可以通过设置标志位让其停止。

class MyThread implements Runnable{
private boolean flag = true;
public void run(){
int i=0;
while(flag){
System.out.println(Thread.currentThread().getName()+" --> 运行,i ="+(i++));
}
}
public void setFlag(boolean flag){
this.flag = flag;
}
}
public class ThreadDemo06{
public static void main(String args[]){
MyThread mt = new MyThread();
new Thread(mt).start();
try{
Thread.sleep(300);
}catch(Exception e){}
//将线程的运行的条件修改了,则肯定停止运行
mt.setFlag(false);
}
}
或者也可以修改成throws Exception

class MyThread implements Runnable{
private boolean flag = true;
public void run(){
int i=0;
while(flag){
System.out.println(Thread.currentThread().getName()+" --> 运行,i ="+(i++));
}
}
public void setFlag(boolean flag){
this.flag = flag;
}
}
public class ThreadDemo06{
public static void main(String args[])throws Exception{
MyThread mt = new MyThread();
new Thread(mt).start();
Thread.sleep(300);
//将线程的运行的条件修改了,则肯定停止运行
mt.setFlag(false);
}
}
发现程序运行一段时间后自己停止运行了哈~~~



多线程面试题:



可以直接参考生产者和消费者问题。

class Num{
int j = 0;
}
class Inc implements Runnable{
private Num n = null;
public Inc(Num n){
this.n = n;
}
public void run(){
while(true){
System.out.println("加:"+Thread.currentThread().getName()+" -->"+n.j++);
}
}
}
class Dec implements Runnable{
private Num n = null;
public Dec(Num n){
this.n = n;
}
public void run(){
while(true){
System.out.println("减:"+Thread.currentThread().getName()+" -->"+n.j--);
}
}
}
public class ThreadDemo07{
public static void main(String args[]){
Num n = new Num();
Inc i = new Inc(n);
Dec d = new Dec(n);
new Thread(i,"加线程A:").start();
new Thread(i,"加线程B:").start();
new Thread(d,"减线程C:").start();
new Thread(d,"减线程D:").start();
}
}
看下效果:






本季重点:



使用Runnable可以实现资源的共享,但是实现之后就必须想办法对资源进行同步,否则会出现数据不正确的情况,但是如果过多的使用了同步,则会发生死锁。
完整的方法定义:
[public|protected|default|private] [synchronized] [static] [final]
返回值类型|void 方法名称(参数列表) [throws 异常]

#############################################################
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息