这里写目录标题
- Runnable
- Runable接口实现多线程
- 使用Runnable接口实现多线程的好处
- 线程同步 - 三个窗口买票
- lock实现同步锁
Runnable
Runable接口实现多线程
-
实现 Runnable 接口
-
定义一个类 MyRunnable 实现 Runnable 接口
-
在 MyRunnable 类中重写
run()
方法 -
创建 Thread 类的对象,把 MyRunnable 对象作为构造方法的参数
-
启动线程
-
demo:
定义一个类作为Runnable接口实现类
package com.itxs.demo05;/*** @Classname : MyRunnable* @Description : TODO* @Author : lin_refuel@qq.com*/
public class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println(Thread.currentThread().getName() + " i = " + i);}}
}
测试类demo01
package com.itxs.demo05;/*** @Classname : demo01* @Description : TODO* @Author : lin_refuel@qq.com*/
public class demo01 {public static void main(String[] args) {MyRunnable mr = new MyRunnable();//创建线程Thread mt01 = new Thread(mr, "线程01");//Runnable接口实现类对象作为参数进行传递Thread mt02 = new Thread(mr, "线程02");Thread mt03 = new Thread(mr, "线程03");//匿名内部类方式实现new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 30; i++) {System.out.println(Thread.currentThread().getName()+" i = " + i);}}},"匿名线程").start();// 线程开启mt01.start();mt02.start();mt03.start();}
}
使用Runnable接口实现多线程的好处
-
相比继承 Thread 类,实现 Runnable 接口的好处
-
避免了 Java 单继承的局限性
-
适合多个程序的代码同时处理一个资源的情况,把线程和程序的代码、数据有效的分离,较好的体现了面向对象程序设计的思想
-
线程同步 - 三个窗口买票
需求:德云社封箱演出共有 100 张门票,设置三个窗口买票,设计模拟买票的程序
思路:
定义一个 SellTickets 实现 Runnable 接口,里面定义一个成员:private int tickets = 100;
在 SellTickets 类中重写
run()
方法,实现买票
判断剩余票数是否大于 0,是就卖,并告知是哪个窗口卖出的
卖掉一张之后要对应减一
没有票了,也可能有人来买,用死循环让买票动作一直持续
顶一个测试类 SellTicketsTest,里面有
main()
方法
创建 SellTickets 类对象
创建三个 Thread 类的对象,把 SellTickets 对象作为构造方法的参数,并给出对应的窗口名称
启动线程
sycnchronized(任意对象){}:同步语句块,多个线程操作同一个资源时,当某个线程执行同步语句块里面的代码时,别的线程是无法执行的,只有当执行同步语句块线程执行完里面同步语句块的内容时,其他线程才能进行访问
-
是否有多线程环境
-
是否有共享数据
-
是否有多条语句操作共享项数据
参考文章
demo:
卖票的动作,注意同步语句块的用法
package com.itxs.demo06;/*** @Classname : SellTickets* @Description : TODO* @Author : lin_refuel@qq.com*/
public class SellTickets implements Runnable {private int tickets = 100;// 门票数量为100@Overridepublic void run() {// 定义死循环,一直进行买票while (true){// 同步语句块,一个窗口抢到卖票权,其他窗口无法卖出同一个票synchronized (this){// 判断门票数是否大于0满足条件进行卖票if(tickets > 0){//打印出票System.out.println(Thread.currentThread().getName() +"正在买第 - "+this.tickets+"张门票");// 每次打印出票后,票数减去1this.tickets --;}}// 每个窗口卖出票后,等待出票try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
test测试类
package com.itxs.demo06;/*** @Classname : test* @Description : TODO 测试类* @Author : lin_refuel@qq.com*/
public class test {public static void main(String[] args) {//创建卖票动作的线程SellTickets st = new SellTickets();// 创建三个窗口进行买票Thread windows01 = new Thread(st, "窗口1");Thread windows02 = new Thread(st, "窗口2");Thread windows03 = new Thread(st, "窗口3");// 开始买票windows01.start();windows02.start();windows03.start();}
}
lock实现同步锁
还是上面的案例,通过lock方式实现线程同步
买票的类
package com.itxs.demo06;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @Classname : SellTickets* @Description : TODO* @Author : lin_refuel@qq.com*/
public class SellTickets implements Runnable {private int tickets = 100;// 门票数量为100private Lock lock = new ReentrantLock();@Overridepublic void run() {// 定义死循环,一直进行买票while (true){// 同步语句块,一个窗口抢到卖票权,其他窗口无法卖出同一个票ticket();// 每个窗口卖出票后,等待出票try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}// 同步方法private /*synchronized*/ void ticket() {//synchronized (this){lock.lock();//上锁// 判断门票数是否大于0满足条件进行卖票if(this.tickets > 0){//打印出票System.out.println(Thread.currentThread().getName() +"正在买第 - "+this.tickets+"张门票");// 每次打印出票后,票数减去1this.tickets --;}//}lock.unlock();//开锁,!!!注意不要忘记开锁}
}
test测试类
package com.itxs.demo06;/*** @Classname : test* @Description : TODO 测试类* @Author : lin_refuel@qq.com*/
public class test {public static void main(String[] args) {//创建卖票动作的线程SellTickets st = new SellTickets();// 创建三个窗口进行买票Thread windows01 = new Thread(st, "窗口1");Thread windows02 = new Thread(st, "窗口2");Thread windows03 = new Thread(st, "窗口3");// 开始买票windows01.start();windows02.start();windows03.start();}
}