java学习之多线程(二)

线程间通讯
  其实就是多个线程在操作同一个资源,但是操作的动作不同。

案例:对姓名性别的设置与读取。
  代码中标志位可以是boolean flag,也可以是int x,x=(x+1)%2。

  加了同步还出错,于是想同步前提:一是2个以上线程是否同步代码(即代码是对同一个资源的操作);二是同一个锁。

wait:
notify():
notifyAll():
都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中呢?
  因为这些方法在操作同步线程时,都必须要标识它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒,不可以对不同锁中的线程进行唤醒。
  也就是说,等待和唤醒必须是同一个锁,而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。

class Res{
    private String name;
    private String sex;
    private boolean flag = false;
    
    public synchronized void set(String name, String sex) {
        while(flag)
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        this.name = name;
        this.sex = sex;
        flag = true;
        this.notifyAll();
    }
    
    public synchronized void out(){
        while(flag)
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(name+"..."+sex);
        flag = false;
        this.notifyAll();
    }
}
//对资源进行设置操作
class Input implements Runnable{
    Res r;

    public Input(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        int x = 0;
        if(x==0){
            r.set("mike","man");
        }else{
            r.set("莉莉","女");
        }
        x = (x+1)%2;
    }
}

//对资源进行读取操作
class OutPut implements Runnable{

    Res r;

    public OutPut(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true)
            r.out();
    }
}

//测试
public class Test{
    

    public static void main(String[] args){
        Res r = new Res();
        Thread t1 = new Thread(new Input(r));
        Thread t2 = new Thread(new OutPut(r));
        t1.start();
        t2.start();
    }
}

线程间通讯--生产者消费者:
  jdk1.5 中提供了多线程升级解决方案,将同步synchronized替换成显示Lock操作,将Object中的wait,notify,notifyAll替换了condition对象,该对象可以对Lock锁进行替换。
该示例中,实现了本方只唤醒对方操作。并且可以执行多个设置和读取操作

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Res{
    private String name;
    private String sex;
    private boolean flag = false;
    private Lock lock = new ReentrantLock();
    private Condition condition_input = lock.newCondition();
    private Condition condition_output = lock.newCondition();


    public void set(String name, String sex) {
        lock.lock();
        try {
            while(flag)
                try {
                    condition_input.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            this.name = name;
            this.sex = sex;
            flag = true;
            condition_output.signal();
        }finally {
            lock.unlock();
        }

    }

    public void out(){
        lock.lock();
        try {
            while(flag)
                try {
                    condition_output.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            System.out.println(name+"..."+sex);
            flag = false;
            condition_input.signal();
        }finally {
            lock.unlock();
        }

    }
}
//对资源进行设置操作
class Input implements Runnable{
    Res r;

    public Input(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        int x = 0;
        if(x==0){
            r.set("mike","man");
        }else{
            r.set("莉莉","女");
        }
        x = (x+1)%2;
    }
}

//对资源进行读取操作
class OutPut implements Runnable{

    Res r;

    public OutPut(Res r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true)
            r.out();
    }
}

//测试
public class Test{


    public static void main(String[] args){
        Res r = new Res();
        Thread t1 = new Thread(new Input(r));
        Thread t2 = new Thread(new OutPut(r));
        t1.start();
        t2.start();
    }
}

--------------------------------------------------------------------------------
多线程:停止线程:
1.定义循环结束标记
  因为线程运行代码一般都是循环,只要控制了循环即可
2.使用interrupt(中断)方法
  该方法是结束线程的冻结状态,使线程回到运行状态中来
注:stop方法已经过时不再使用。

stop方法已经过时,如何停止线程?
  只有一种,run方法结束。
  开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
  显而易见,可以想到用标记来停止线程,但是特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清楚,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
Thread类提供该方法interrupt();
--------------------------------------------------------------------------------
多线程:守护线程:(类似后台线程):当正在运行的线程都是守护线程时,java虚拟机退出。该方法必须在启动线程前调用。看api
看见的线程都是前台线程,而后台线程的特点是:当所有的前台线程都结束后后台线程也会结束。

多线程:Jion方法:等待该线程终止。
特点:当a线程执行到了b线程的.join()方法时,a就会等待,等b线程都执行完,a才会执行。jion可以用来临时加入线程执行。

优先级&yield方法
yield:暂停当前正在执行的线程对象,并执行其他线程。

扫描二维码关注公众号,回复: 1775488 查看本文章

在开发中如何使用多线程--使用匿名内部类达到并发效果

public static void main(String[] args){
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i=0;i<60;i++)
                    System.out.println(Thread.currentThread().getName()+"..."+i);
            }
        };
        new Thread(r).start();
    }
}

猜你喜欢

转载自www.cnblogs.com/zhaohuan1996/p/9237647.html