/* * 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到哪里加上了锁,在哪里释放了锁 * 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock * * Lock: void lock():获取锁 * void unlock():释放锁 * ReentrantLock是Lock的实现类 * */
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()); } }
来源:oschina
链接:https://my.oschina.net/u/2954646/blog/3222663