多线程
一、创建多线程方式一:
继承Thread类,重写run()方法,调用start开启线程
二、创建多线程方式二:
实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口实现类,调用start方法。
龟兔赛跑
实现Runnable接口
package com.wei.jiechu.duoxiancheng;
//龟兔赛跑
public class Race implements Runnable{
//胜利者
private static String winner;
@Override
public void run() {
for (int i = 0; i <=100; i++) {
//模拟兔子休息
if (Thread.currentThread().getName().equals("兔子")&& i%10==0){
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
boolean flag=gameOver(i);
//如果比赛结束了,就停止程序
if(flag){
break;
}
//当前线程跑了多少步
System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
}
}
//判断是否完成比赛
private boolean gameOver(int steps){
//判断是否有胜利者
if(winner!=null){
return true;
}{
if(steps>=100){
winner=Thread.currentThread().getName();
System.out.println("winner is"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race=new Race();
new Thread(race,"兔子").start();
new Thread(race,"乌龟").start();
}
}
三、创建多线程方式三:
实现Callable接口(了解即可)(弹幕说面试重灾区)
1.实现Callable接口,需要返回值类型
2.重写call方法,需要抛出异常
3.常见目标对象
4.常见执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
5.提交执行:Futureresult1=ser.submit(t1);
6.获取结果:boolean r1=result1.get()
7.关闭服务:ser.shutdownNow();
四、线程停止
package com.wei.jiechu.duoxiancheng;
public class TestStop implements Runnable{
//1.设置一个标志位
private boolean flag=true;
@Override
public void run() {
int i=0;
while (flag){
System.out.println("run....Thread"+i++);
}
}
//2.设置一个公开的方法停止线程,转换标志位
public void stop(){
this.flag=false;
}
public static void main(String[] args) {
TestStop testStop =new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i==900){
//调用stop方法切换标志位,让线程停止
testStop.stop();
System.out.println("线程该停止了");
}
}
}
}
五、模拟网络延时
模拟网络延时
sleep
package com.wei.jiechu.duoxiancheng;
//模拟网络延时
public class YanShi implements Runnable{
private int ticketnums=10;
@Override
public void run() {
while(true){
if(ticketnums<=0){
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketnums--+"票");
}
}
public static void main(String[] args) {
YanShi ticket=new YanShi();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛党").start();
}
}
模拟倒计时
package com.wei.jiechu.duoxiancheng;
//模拟倒计时
public class JiShi {
public static void main(String[] args) throws InterruptedException {
tenDown();
}
public static void tenDown() throws InterruptedException {
int num=10;
while(true){
Thread.sleep(1000);
System.out.println(num--);
if(num<=0){
break;
}
}
}
}
打印当前系统时间
System.currentTimeMillis()
package com.wei.jiechu.duoxiancheng;
import java.text.SimpleDateFormat;
import java.util.Date;
public class JiShi {
public static void main(String[] args) {
//打印当前系统时间
Date startTime=new Date(System.currentTimeMillis());//获取系统当前时间
while(true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime=new Date(System.currentTimeMillis());//更新时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程插队
join
package com.wei.jiechu.duoxiancheng;
public class ChaDui implements Runnable {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("线程vip来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
//启动我们的线程
ChaDui testJoin=new ChaDui();
Thread thread=new Thread(testJoin);
thread.start();
//主线程
for (int i = 0; i < 500; i++) {
if(i==200){
thread.join();//插队
}
System.out.println("main"+i);
}
}
}
六、线程状态
观察线程状态
package com.wei.jiechu.duoxiancheng;
//观察测试线程的状态
public class ZhuangTai {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i = 0; i < 2; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("//");
});
//观察状态
Thread.State state=thread.getState();
System.out.println(state);//NEW
//观察启动后
thread.start();//启动线程
state =thread.getState();
System.out.println(state);//Run
//只要线程不停止,就一直输出状态
while (state!=Thread.State.TERMINATED){
Thread.sleep(100);
state=thread.getState();//更新线程状态
System.out.println(state);//输出状态
}
}
}
测试线程的优先级
Priority
package com.wei.jiechu.duoxiancheng;
public class YouXianJi {
public static void main(String[] args) {
//主线程默认优先级
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority myPriority=new MyPriority();
Thread t1=new Thread(myPriority);
Thread t2=new Thread(myPriority);
Thread t3=new Thread(myPriority);
Thread t4=new Thread(myPriority);
//先设置优先级,再启动
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
守护线程
Daemon(true)
package com.wei.jiechu.duoxiancheng;
//测试守护线程
//上帝守护你
public class ShouHu {
public static void main(String[] args) {
God god=new God();
You you=new You();
Thread thread=new Thread(god);
thread.setDaemon(true);//默认是false表示是用户线程,正常的线程都是用户线程...
thread.start();//上帝守护线程启动
new Thread(you).start();//你 用户线程启动...
}
}
//上帝
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝保佑着你");
}
}
}
//你
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生都开心的活着");
}
System.out.println("================goodbye!world!===========");//Hello,World!
}
}
七、并发 线程同步 队列 锁
同步方法锁机制:synchronized
同步块:synchronized(Obj){}
三大不安全案例
不安全的买票
package com.wei.thread;
//不安全的买票
public class XCTongBu {
public static void main(String[] args) {
Text text=new Text();
new Thread(text,"小明").start();
new Thread(text,"老师").start();
new Thread(text,"黄牛党").start();
}
}
class Text implements Runnable{
//票
private int nums=10;
boolean flag =true;//外部停止方法
@Override
public void run() {
//买票
while (flag){
buy();
}
}
private void buy(){
//判断是否有票
if (nums<=0){
flag=false;
return;
}
/* try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
//买票
System.out.println(Thread.currentThread().getName()+"拿到"+nums--);
}
}
不安全的取钱
package com.wei.thread;
//不安全的取钱
//两个人去银行取钱,账户
public class bank {
public static void main(String[] args) {
//账户
Account account=new Account(100,"结婚基金");
Drawing you =new Drawing(account,50,"你");
Drawing girlFriend =new Drawing(account,100,"girlFriend");
you.start();
girlFriend.start();
}
}
//账户
class Account{
int money;//余额
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行:模拟取款
class Drawing extends Thread{
//账户
Account account;
//取了多少钱
int drawingMoney;
//现在手里有多少钱
int nowMoney;
public Drawing(Account account,int drawingMoney,String name){
super(name);
this.account=account;
this.drawingMoney=drawingMoney;
}
@Override
public void run() {
//判断有没有钱
if (account.money-drawingMoney<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
//sleep可以放大问题的发生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额=余额-你取的钱
account.money=account.money-drawingMoney;
//你手里的钱
nowMoney=nowMoney+drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
System.out.println(this.getName()+"手里的钱:"+nowMoney);
}
}
线程不安全的集合
package com.wei.thread;
import java.util.ArrayList;
import java.util.List;
//线程不安全的集合
public class unsafeList {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
三大不安全案例改后
不安全的买票 改
synchronized
package com.wei.thread;
//不安全的买票
public class XCTongBu {
public static void main(String[] args) {
Text text=new Text();
new Thread(text,"小明").start();
new Thread(text,"老师").start();
new Thread(text,"黄牛党").start();
}
}
class Text implements Runnable{
//票
private int nums=10;
boolean flag =true;//外部停止方法
@Override
public void run() {
//买票
while (flag){
buy();
}
}
//synchronized 同步方法,锁的是this
private synchronized void buy(){
//判断是否有票
if (nums<=0){
flag=false;
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//买票
System.out.println(Thread.currentThread().getName()+"拿到"+nums--);
}
}
不安全的取钱 改
synchronized块
package com.wei.thread;
//不安全的取钱
//两个人去银行取钱,账户
public class bank {
public static void main(String[] args) {
//账户
Account account=new Account(100,"结婚基金");
Drawing you =new Drawing(account,50,"你");
Drawing girlFriend =new Drawing(account,100,"girlFriend");
you.start();
girlFriend.start();
}
}
//账户
class Account{
int money;//余额
String name;//卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行:模拟取款
class Drawing extends Thread{
//账户
Account account;
//取了多少钱
int drawingMoney;
//现在手里有多少钱
int nowMoney;
public Drawing(Account account,int drawingMoney,String name){
super(name);
this.account=account;
this.drawingMoney=drawingMoney;
}
@Override
public void run() {
synchronized (account){
//判断有没有钱
if (account.money-drawingMoney<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
//sleep可以放大问题的发生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额=余额-你取的钱
account.money=account.money-drawingMoney;
//你手里的钱
nowMoney=nowMoney+drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
System.out.println(this.getName()+"手里的钱:"+nowMoney);
}
}
}
线程不安全的集合 改
package com.wei.thread;
import java.util.ArrayList;
import java.util.List;
//线程不安全的集合
public class unsafeList {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
锁
死锁
package com.wei.thread;
//死锁:多个线程互相抱着对方需要的资源,然后形成僵持
public class DeadLock {
public static void main(String[] args) {
Makeup g1=new Makeup(0,"灰姑凉");
Makeup g2=new Makeup(1,"白雪公主");
g1.start();
g2.start();
}
}
//口红
class Lipstick{
}
//镜子
class Mirror{
}
class Makeup extends Thread {
//需要的资源只有一份,用static来保证只有一份
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;//选择
String girlName;//使用化妆品的人
Makeup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//化妆,互相持有对方的锁,就是需要拿到对方的资源
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) {//获得口红的锁
System.out.println(this.girlName + "获得口红的锁");
Thread.sleep(1000);
synchronized (mirror) {//一秒钟后想获得镜子
System.out.println(this.girlName + "获得镜子的锁");
}
}
} else {
synchronized (mirror) {//获得镜子的锁
System.out.println(this.girlName + "获得镜子的锁");
Thread.sleep(2000);
synchronized (lipstick) {//一秒钟后想获得口红
System.out.println(this.girlName + "获得口红的锁");
}
}
}
}
}
Lock锁
ReentrantLock类实现了Lock
可重入锁
- 从JDK 5.0开始,java提供了更强大的在线同步机制——通过显示定义同步锁对象来实现同步。同步锁使用Lock对象充当。
- java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
- ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语意,在实现线程安全的控制中,比较常用的是PeentrantLock,可以显示加锁、释放锁。
synchronized与lock的对比 - Lock是显示锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放
- Lock只有代码块锁,synchronized有代码块锁和方法锁
- 使用Lock锁,JVM将花费较少的事件来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
加锁之前
package com.wei.thread;
import java.util.concurrent.locks.ReentrantLock;
//测试Lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2=new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums=10;
@Override
public void run() {
while (true) {
if (ticketNums > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
} else {
break;
}
}
}
}
加锁之后
package com.wei.thread;
import java.util.concurrent.locks.ReentrantLock;
//测试Lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2=new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums=10;
//定义lock锁
ReentrantLock lock =new ReentrantLock();
@Override
public void run() {
try {
while (true) {
lock.lock();//加锁
if (ticketNums > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
} else {
break;
}
}
}finally {
//解锁
lock.unlock();
}
}
}