线程(二)

♀尐吖头ヾ 提交于 2020-04-07 09:54:52
/*
* 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到哪里加上了锁,在哪里释放了锁
* 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
*
* Lock: void lock():获取锁
*       void unlock():释放锁
*   ReentrantLockLock的实现类
* */
public class SellTicket implements Runnable {
    //定义100张票
    private static int tickets=100;
    //定义锁对象
    private Lock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
            //加锁
            lock.lock();
                    if (tickets>0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
                    }
            }finally {
                //释放锁
                lock.unlock();
            }
        }

    }
}
public class SellTicketDemo {
    public static void main(String[] args) {
        //创建资源对象
        SellTicket st=new SellTicket();
        //创建三个线程
        Thread t1=new Thread(st,"窗口1");
        Thread t2=new Thread(st,"窗口2");
        Thread t3=new Thread(st,"窗口3");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

=================================死锁=================================

public class MyLock {
    //创建两把锁对象
    public static final Object objA=new Object();
    public static final Object objB=new Object();
}
public class DieLock extends Thread {
    private boolean flag;

    public DieLock(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            synchronized (MyLock.objA){
                System.out.println("if objA");
                synchronized (MyLock.objB){
                    System.out.println("if ObjB");
                }
            }
        }else {
            synchronized (MyLock.objB){
            System.out.println("else objB");
            synchronized (MyLock.objA){
                System.out.println("else objA");
            }
        }
        }
    }
}
public static void main(String[] args) {
    DieLock dl1=new DieLock(true);
    DieLock dl2=new DieLock(false);
    //启动线程
    dl1.start();
    dl2.start();
}

===========================线程间通信===========================

public class Student {
    String name;
    int age;
}
public class SetThread implements Runnable {
    private Student s;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        //Student s=new Student();
       s.name="雨飞扬";
       s.age=22;
    }
}
public class GetThread implements Runnable{
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        System.out.println(s.name+"==="+s.age);
    }
}
public static void main(String[] args) {
    //创建资源
    Student s=new Student();
    //设置和获取的类
    SetThread st=new SetThread(s);
    GetThread gt=new GetThread(s);
   //线程类
    Thread t1=new Thread(st);
    Thread t2=new Thread(gt);
    //启动线程
    t1.start();
    t2.start();
}
1:多线程有几种实现方案,分别是哪几种?
   两种。

   继承Thread   实现Runnable接口

   扩展一种:实现Callable接口。这个得和线程池结合。

2:同步有几种方式,分别是什么?
   两种。

   同步代码块
   同步方法
3:sleep()wait()方法的区别
   sleep():必须指时间;不释放锁。
   wait():可以不指定时间,也可以指定时间;释放锁。
4:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
   因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
Object代码任意的对象,所以,定义在这里面。

 

public class Student {
    String name;
    int age;
}
public class GetThread implements Runnable{
    private  Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true){
            synchronized (s){
                System.out.println(s.name+"---"+s.age);
            }
        }
    }
}
public class SetThread implements Runnable {
    private  Student s;
    private int x=0;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true){
            synchronized (s){
                if (x%2==0){
                 //刚走到这里,就被别人抢到了执行权
                    s.name="雨飞扬";
                    s.age=22;
                }  else {
                //刚走到这里,就被别人抢到了执行权
                    s.name="留意";
                    s.age=26;
                }
                x++;
            }
        }
    }
}
/**
* 分析: 资源类: Student
*       设置学生数据: SetThread(生产者)
*       获取学生数据: GetThread(消费者)
*       测试类: StudentDemo
* 问题1: 按照思路写代码,发现数据每次都是: null---0
* 原因: 我们再每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个?
* 如何实现呢?  在外界把这个数据创建出来,通过构造方法创建给其他的类
*   问题2: 为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
*       A:同一个数据出现多次
*       B:姓名和年龄不匹配
*   原因:
*       A:同一个数据出现多次
*           CPU的一点点时间片的执行权,就足够你执行很多次
*       B:姓名和年龄不匹配
*           线程运行的随机性
*   线程安全问题:
*       A:是否是多线程环境  是
*       B:是否有共享数据  是
*       C:是否有多条语句操作共享数据  是
* 解决方案:
*   加锁
*   注意: A:不同种类的都要加锁
*         B:不同种类的线程加的锁必须是同一把
* */
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源类
        Student s=new Student();
        //设置和获取的类
        SetThread st=new SetThread(s);
        GetThread gt=new GetThread(s);
        //线程类
        Thread t1=new Thread(st);
        Thread t2=new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }

}

==============================有就消费, 没有就等待, 依次打印==============================

public class Student {
    private String name;
    private  int age;
    /**默认情况下是没有数据,如果是true,说明有数据*/
    private boolean flag;
    public synchronized void set(String name,int age){
        //如果有数据就等待
        if (this.flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
            //设置数据
            this.name=name;
            this.age=age;
            //修改标记
            this.flag=true;
            this.notify();

    }
    public synchronized void get(){
        //如果没有数据就等待
        if (!this.flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
            //获取数据
            System.out.println(this.name+"---"+this.age);
            //修改标记
            this.flag=false;
            this.notify();

    }

}
public class GetThread implements Runnable{
    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true){
           s.get();
        }
    }
}
public class SetThread implements Runnable {
    private Student s;
    private int x = 0;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            if (x % 2 == 0) {
                s.set("楼上", 23);
            } else {
                s.set("临朐", 34);
            }
            x++;
        }
    }
}
public static void main(String[] args) {
    //创建资源
    Student s = new Student();
    //设置和获取类
    SetThread st = new SetThread(s);
    GetThread gt = new GetThread(s);
    //线程类
    Thread t1 = new Thread(st);
    Thread t2 = new Thread(gt);
    //启动线程
    t1.start();
    t2.start();
}

===============================线程组===============================

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
}
/**
* 线程组: 把多个线程组合在一起
* 它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制
* */
public class ThreadGroupDemo {
    public static void main(String[] args) {

       // method1();

        method2();

    }

    private static void method2() {
       //public ThreadGroup(String name)构造一个新线程组
        ThreadGroup tg=new ThreadGroup("线程组");
        MyRunnable mr=new MyRunnable();
   //public Thread(ThreadGroup group,Runnable target,String name)
        Thread t1=new Thread(tg,mr,"临时");
        Thread t2=new Thread(tg,mr,"历史");
        System.out.println(t1.getThreadGroup().getName());
        System.out.println(t2.getThreadGroup().getName());
        //public final void setDaemon(boolean daemon)更改此线程组的后台程序状态。
        tg.setDaemon(true);
    }
private static void method1() {
    MyRunnable mr=new MyRunnable();
    Thread t1=new Thread(mr,"liuqiu");
    Thread t2=new Thread(mr,"toString");
    // public final ThreadGroup getThreadGroup()返回该线程所属的线程组。
    ThreadGroup tg=t1.getThreadGroup();
    ThreadGroup tg2=t2.getThreadGroup();
    //public final String getName()返回此线程组的名称。
    String name1=tg.getName();
    String name2=tg2.getName();
    System.out.println(name1);
    System.out.println(name2);
    //通过结果我们知道了:线程默认情况下属于main线程组
    //通过下面的测试,你应该能够看到,默认情况下,所有的线程都属于同一组
    System.out.println(Thread.currentThread().getThreadGroup().getName());
}
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!