实现 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 {
@Override
public 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() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName()+" i = " + i);
}
}
},"匿名线程").start();
// 线程开启
mt01.start();
mt02.start();
mt03.start();
}
}
相比继承 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
@Override
public void run() {
// 定义死循环,一直进行买票
while (true){
// 同步语句块,一个窗口抢到卖票权,其他窗口无法卖出同一个票
synchronized (this){
// 判断门票数是否大于0满足条件进行卖票
if(tickets > 0){
//打印出票
System.out.println(Thread.currentThread().getName() +"正在买第 - "+this.tickets+"张门票");
// 每次打印出票后,票数减去1
this.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方式实现线程同步
买票的类
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;// 门票数量为100
private Lock lock = new ReentrantLock();
@Override
public 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+"张门票");
// 每次打印出票后,票数减去1
this.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();
}
}