package hai.bok.thread.dem01;
/**
* @auther 海文宇
* @Date 2022/3/15 22:46
* @Description
*/
public class MyThread extends Thread{
//重写run方法
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("子线程:"+i);
}
}
}
package hai.bok.thread.dem01;
import hai.bok.thread.dem01.MyThread;
/**
* @auther 海文宇
* @Date 2022/3/15 22:43
* @Description
* 线程启动的两种方式
* 1.继承呢过Thread类
* 步骤:1.自定义一个类继承Thread类
* 2.重写run方法
* 3.创建线程
* 4.启动线程
* 注意:
* 1.开启线程是调用的线程对象是start方法,不是run方法
* 调用run方法 没有多线程的效果,就跟调用你的普通方法一样.
* 2.线程不能多次启动,只能启动一次,(只能调用start方法一次)
* 2.实现Runnable类
* 步骤:1.自定义一个类实现Runnable类
* 2.重写run方法,编写子线程的任务
* 3.创建Thread类,用构造方法把Runnable接口的子类作为参数传入
* 4.启动线程
*
*/
public class TestThread {
public static void main(String[] args) {
//创建线程对象
MyThread myThread = new MyThread();
//启动线程对
myThread.start();//有启动的话会出现线程抢占的效果
// myThread.run();//可以执行,但是没有线程抢占的效果
//主线程
for (int i = 0; i < 10000; i++) {
System.out.println("主线程:"+i);
}
}
}
方式二:实现Runnable接口
package hai.bok.thread.dem01;
/**
* @auther 海文宇
* @Date 2022/3/15 23:10
* @Description
* 使用Runnable接口实现
*/
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 1000; i < 2000; i++) {
System.out.println("子线程:"+i);
}
}
}
package hai.bok.thread.dem01;
import hai.bok.thread.dem01.MyRunnable;
/**
* @auther 海文宇
* @Date 2022/3/15 23:12
* @Description
*/
public class TestRunnable {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
//创建Thread类,用构造方法把Runnable接口的子类作为参数传入
Thread thread=new Thread(mr);
//启动线程
thread.start();
//主线程
for (int i = 1; i <= 100; i++) {
System.out.println("主线程:"+i);
}
}
}
方式三:实现Callable接口的方式
package hai.bok.thread.dem02;
import java.util.concurrent.Callable;
/**
* @auther 海文宇
* @Date 2022/3/15 23:36
* @Description
* 实现Callable的接口的方式
*/
public class CallableThread implements Callable<Integer> {
private int m;
private int n;
public CallableThread() {
}
public CallableThread(int m, int n) {
this.m = m;
this.n = n;
}
public int getM() {
return m;
}
public void setM(int m) {
this.m = m;
}
public int getN() {
return n;
}
public void setN(int n) {
this.n = n;
}
//run方法有返回值,还带了一个异常
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = m; i <=n; i++) {
System.out.println("子线程"+i);
sum+=i;
}
return sum;
}
}
package hai.bok.thread.dem02;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* @auther 海文宇
* @Date 2022/3/15 23:32
* @Description
* 之前的线程的启动,run()方法没有返回值,在主线程中没有办法获取子线程的返回结果
* 所有这里可以使用Callable接口的方式来开启线程
* 需求:计算m~n的和
*/
public class Test01 {
public static void main(String[] args) {
//使用Callable接口,创建类
CallableThread ct=new CallableThread(1,100);
//创建FutureTast对象,有返回值类型是Integer;
FutureTask<Integer> task=new FutureTask<Integer>(ct);
//创建线程对象,把task当做参数传递
Thread thread=new Thread(task);
//启动线程
thread.start();
//主线程
for (int i = 0; i < 1000; i++) {
System.out.println("主线程:"+i);
}
try {
Integer sum = task.get();//获取子线程的结果
System.out.println("子线程的计算结果:"+sum);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package hai.bok.thread.dem03;
/**
* @auther 海文宇
* @Date 2022/3/16 0:12
* @Description
* 1.使用匿名内部类 方式开启线程,节约内存资源,同时也会更加简洁
* 2.当匿名内部类方式同时继承Thread类方式和实现Runnable接口方式两种启动,以Thread类方式优先
*/
public class Test01 {
public static void main(String[] args) {
//没有重写run方法分配任务,匿名线程对象启动.
new Thread().start();
//匿名内部类线程对象的启动,没有run方法,也没有分配任务
new Thread(){}.start();
//匿名内部类线程对象的启动,重写run方法
new Thread(){
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("匿名内部类继承Thread类线程对象的启动方式:"+i);
}
}
}.start();
//匿名内部类Tread类线程对象实现Runnable接口
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("匿名内部类Tread类线程对象实现Runnable接口:"+i);
}
}
}).start();
//匿名内部类继承Tread类线程对象同时实现Runnable接口的方式
new Thread(new Runnable() {
@Override
public void run() {
//使用Runnable方式
for (int i = 0; i < 1000; i++) {
System.out.println("匿名内部类实现Runnable接口2:"+i);
}
}
}){
//继承Thread类实现方式
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("匿名内部类继承Thread类线程对象的启动方式2:"+i);
}
}
}.start();;
}
}
构造方法:
方法:
2.1.线程优先级的特点:
2.2 设置优先级的字段和方法
注意
设置了优先级,也不能够从优先级的测试具体的体现一定性,(也就是说,设置了优先级,优先级高的不一定就是一定先执行完.),只是说线程或得CUP执行的时间会多一点,线程的任务耗费时间设置的长一点,效果体现更加明显.
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 21:05
* @Description
*/
public class PriporityThread extends Thread {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println(getName()+":"+i);
}
}
}
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 21:04
* @Description
* 练习优先级
*/
public class Test01 {
public static void main(String[] args) {
//差创建3个子线程
PriporityThread p1 = new PriporityThread();
PriporityThread p2 = new PriporityThread();
PriporityThread p3 = new PriporityThread();
//设置三个线程的名字
p1.setName("李四");
p2.setName("张三");
p3.setName("王五");
//设置优先级,优先级的范围是1~10,超出这个范围会报错
p1.setPriority(Thread.MAX_PRIORITY);//10
p2.setPriority(Thread.NORM_PRIORITY);//5
p3.setPriority(Thread.MIN_PRIORITY);//1
//启动线程
p1.start();
p2.start();
p3.start();
}
}
package hai.bok.thread.dem05;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @auther 海文宇
* @Date 2022/3/16 21:37
* @Description
*/
public class SleepTread extends Thread {
@Override
public void run() {
//死循环
while (true){
//每休眠一秒显示一次时间
String format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date());
System.out.println(getName()+":"+format);
try {
Thread.sleep(1000);//休眠一秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 21:45
* @Description
*/
public class TestSleepThread {
public static void main(String[] args) {
SleepTread st = new SleepTread();
st.setName("时钟");
st.start();
}
}
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 21:55
* @Description
*/
public class JoinThread extends Thread{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName()+":"+i);
}
}
}
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 21:57
* @Description
*/
public class TestJoinThread {
public static void main(String[] args) {
//创建3个线程
JoinThread j1 = new JoinThread();
JoinThread j2 = new JoinThread();
JoinThread j3 = new JoinThread();
//设置名字
j1.setName("张三");
j2.setName("李四");
j3.setName("王五");
//打开线程
j1.start();
try {
//j1子线程加入,优先让这个线程执行.
j1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
j2.start();
j3.start();
}
}
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 22:45
* @Description
*/
public class YieldThread extends Thread{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName()+":"+i);
//让出线程执行权,让出后自己又会去排队等待cup的执行权,会和其他的线程抢夺资源
Thread.yield();
}
}
}
package hai.bok.thread.dem05;
/**
* @auther 海文宇
* @Date 2022/3/16 22:49
* @Description
*/
public class TestYield {
public static void main(String[] args) {
YieldThread t1 = new YieldThread();
YieldThread t2 = new YieldThread();
t1.setName("哥哥");
t2.setName("妹妹");
t1.start();
t2.start();
}
}
package hai.bok.thread.dem06;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @auther 海文宇
* @Date 2022/3/16 23:41
* @Description
* 方式一:继承Thread类的方式
*/
public class SellTickeys extends Thread{
private static int tickets=100;//100张票属于3个窗口,100属于共享数据
public static Lock lock = new ReentrantLock();
//java.util.concurrent.locks Interface Lock
//Lock锁对象,void lock() 获得锁。void unlock() 释放锁。
@Override
public void run() {
//模拟售票
//解决方式一:同步代码块synchronized(锁对象){}
/*synchronized (MyLock.LOCK){//可以使用this,当前类,定义的类作为一把锁
while(true){
if(tickets>0){
//设置休眠
try {
//线程休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"正在售出第"+(tickets--)+"张票");
}
}
}*/
//解决方式二:
//sellTickets();
//解决方式三:Java提供的锁机制Lock锁
//使用try...finally{}来加锁和释放锁,如果try块有异常,一定会执行finally释放锁的操作
try {
//加锁
lock.lock();
while (true){
if (tickets > 0){
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() + "正在售出第" + (tickets--) + "张票");
}
}
} finally {
//释放锁
lock.unlock();
}
//使用JDK提供Lock锁,不需要我们自己定义锁的
//直接使用它的方法就好了,这个使用更加方便,更加满足面向对象思想
}
// 解决方式二:同步方法public synchronized 返回值 方法名(参数){}
/**
* 三个子线程对象都可以调用这个普通方法,而不是三个方法属
* 于三个子线程对象的,应该是一份这个方法给三个子线程对象使用,这样才能真正上锁
* 所以方法得用static修饰
* */
public static synchronized void sellTickets(){//
while(true){
//解决方式一:同步代码块synchronized(锁对象){}
if(tickets>0){
//设置休眠
try {
//线程休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"正在售出第"+(tickets--)+"张票");
}
}
}
}
//定义一把锁类
class MyLock{
public static final MyLock LOCK=new MyLock();
}
package hai.bok.thread.dem06;
/**
* @auther 海文宇
* @Date 2022/3/16 23:49
* @Description
*/
public class TestSellTickets {
public static void main(String[] args) {
SellTickeys t1 = new SellTickeys();
SellTickeys t2 = new SellTickeys();
SellTickeys t3 = new SellTickeys();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
//启动
t1.start();
t2.start();
t3.start();
}
}
package hai.bok.thread.dem06;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @auther 海文宇
* @Date 2022/3/17 1:06
* @Description
*/
public class SellTicketsRunnable implements Runnable{
private static int tickets=100;
private static Lock lock=new ReentrantLock();
@Override
public void run() {
// 解决方式一:同步代码块
/* synchronized (MyLock_.LOCK){
while (true){
if(tickets>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"正在售出第"+(tickets--)+"张票");
}
}
}*/
//解决方式二;
// sellTickets();
//解决方式三
try{
lock.lock();
while(true){
//解决方式一:同步代码块synchronized(锁对象){}
if(tickets>0){
//设置休眠
try {
//线程休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"正在售出第"+(tickets--)+"张票");
}
}
}finally {
lock.unlock();
}
}
public static synchronized void sellTickets(){//
while(true){
//解决方式一:同步代码块synchronized(锁对象){}
if(tickets>0){
//设置休眠
try {
//线程休眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"正在售出第"+(tickets--)+"张票");
}
}
}
}
class MyLock_ {
public static final MyLock LOCK=new MyLock();
}
package hai.bok.thread.dem06;
/**
* @auther 海文宇
* @Date 2022/3/17 1:09
* @Description
*/
public class Test01 {
public static void main(String[] args) {
SellTicketsRunnable tr = new SellTicketsRunnable();
Thread thread1 = new Thread(tr);
Thread thread2 = new Thread(tr);
Thread thread3 = new Thread(tr);
thread1.setName("窗口1:");
thread2.setName("窗口2:");
thread3.setName("窗口3:");
thread1.start();
thread2.start();
thread3.start();
}
}
死锁: 死锁指多个线程在执行过程中,他们在抢夺资源的时候,产生的一种相互等待的现象.
线程组:把多个线程分为一个组,方便统一管理多个线程.
Java API提供这些对线程的一个分组,目的就是可以把一个组的多个线程当做一个单元的一个组的,对一个组的线程再访问的时候就方便直接对他们由一个操作.
package hai.bok.thread.dem08;
/**
* @auther 海文宇
* @Date 2022/3/18 16:06
* @Description
*/
public class Test01MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
package hai.bok.thread.dem08;
import java.util.ArrayList;
import java.util.List;
/**
* @auther 海文宇
* @Date 2022/3/18 16:05
* @Description
*/
public class Test01 {
public static void main(String[] args) {
Test01MyRunnable myRunnable=new Test01MyRunnable();
//第一组
ThreadGroup tg1=new ThreadGroup("三国演义");//分组名称
Thread t1=new Thread(tg1,myRunnable,"刘备");
Thread t2=new Thread(tg1,myRunnable,"曹操");
Thread t3=new Thread(tg1,myRunnable,"孙权");
//第二组
ThreadGroup tg2=new ThreadGroup("西游记");
Thread t4=new Thread(tg2,myRunnable,"孙悟空");
Thread t5=new Thread(tg2,myRunnable,"沙悟净");
Thread t6=new Thread(tg2,myRunnable,"猪八戒");
//启动
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
// activeCount() 返回此线程组中活动线程的估计数
// getName()返回此线程组的名称。
System.out.println(t1.getName());
System.out.println(t3.getThreadGroup().getName());
System.out.println(tg2.activeCount());
tg1.setDaemon(true);//设置守护线程
tg2.stop();//终止一个组
//获取主线程的名称
Thread main=Thread.currentThread();
String name = main.getThreadGroup().getName();
System.out.println(name);
}
}
生产者消费者模型
注意: 顺序和加锁,不会抛出异常,如果没有按照顺序先唤醒后等待,执行的时候会抛出异常。
玩具类
package hai.bok.thread.dem09;
/**
* @auther 海文宇
* @Date 2022/3/18 21:34
* @Description
* 生产者消费者问题
* 玩具类
*/
public class Toy {
//属性:名称,数量,是否有商品玩具
private String name;
private int num;
private boolean flag;//true,有玩具,false,没有玩具
public Toy() {
}
public Toy(String name, int num, boolean flag) {
this.name = name;
this.num = num;
this.flag = flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
生产者类:
package hai.bok.thread.dem09;
/**
* @auther 海文宇
* @Date 2022/3/18 21:38
* @Description
* 生产者
* 先判断是否有玩具
* 如果有,就等待消费者消费,wait
* 如果没有 ,就需要生产,生产完之后通知消费者,notify
*/
public class setThread extends Thread{
//玩具类
private Toy t;
//玩具种类有很多,可以生产多种,或者来控制生产个数
private int i;
public setThread() {
}
public setThread(Toy t) {
this.t = t;
}
public Toy getT() {
return t;
}
public void setT(Toy t) {
this.t = t;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
@Override
public void run() {
while (true){
//锁
synchronized (t){
//判断是否有玩具类
if(t.isFlag()){
//有,就等待
try {
t.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有,就需要生产,生产完之后通知消费者,notify
if(i%2==0){//偶数,生产叮当猫玩具,生产数量为10个
t.setName("叮当猫");
t.setNum(10);
}else {//基数,生产汤姆猫
t.setName("汤姆猫");
t.setNum(5);
}
i++;
//要生产,设置true,代表有数据,设置false,代表没有数据.
//设置标志位,代表这里有数据了
t.setFlag(true);
//生产完之后通知消费者,notify
t.notify();
}
}
}
}
消费者类:
package hai.bok.thread.dem09;
/**
* @auther 海文宇
* @Date 2022/3/18 21:58
* @Description
* 消费者
* 先判断是否有玩具
* 如果没有有,就等待生产者生产
* 如果有,就消费
*/
public class GetThread extends Thread {
//玩具类
private Toy t;
public GetThread() {
}
public GetThread(Toy t) {
this.t = t;
}
@Override
public void run() {
while (true){
//一把锁
synchronized (t){
//先判断是否有玩具
if(!t.isFlag()){//如果没有,就等待生产者生产
try {
t.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果有,就消费
String toyName = t.getName();//获取玩具名称
int toyNum = t.getNum();//获取数量
System.out.println(toyName+"|"+toyNum);
//消费后,数量减一
t.setNum(--toyNum);
//消费完了,就通知生产者生产
if(toyNum<=0){
//设置标记位,代表没有玩具
t.setFlag(false);
//通知生产
t.notify();
}
}
}
}
}
测试类:
package hai.bok.thread.dem09;
/**
* @auther 海文宇
* @Date 2022/3/18 22:12
* @Description
*/
public class Test {
public static void main(String[] args) {
//玩具类
Toy toy = new Toy();
//生产者线程
setThread st = new setThread(toy);
//消费者线程
GetThread gt = new GetThread(toy);
st.start();
gt.start();
}
}