多线程入门

一、多线程

1、概念:

多任务同时执行就是多线程,如果没有任务,就不需要使用多线程

线程和进程之间的区别:

进程:资源分配的最小单位

线程:cpu调度的最小单位

一个进程可以包含1~n个线程

2、线程开启的方式:(重要)

2.1 run()方法:

多线程的入口

定义代码|调用其他方法都可以

调用start()方法,开启多线程后,Java 虚拟机会调用该线程的 run 方法。

2.2 三种开启线程的方式:

  • 继承Thread类,重写run()方法

创建子类对象,调用start()方法,开启多线程

public class ThreadDemo01 extends Thread { 
public static void main(String[] args) { 
//线程开启方法 
//2.创建子类对象,调用start()方法,开启多线程 
//void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
 ThreadDemo01 td=new ThreadDemo01();
 td.start(); 
//或 Thread(Runnable target, String name) 分配新的 Thread 对象。 
new Thread(new ThreadDemo01(),"线程1").start(); 
} /
/1.继承Thread类,重写run方法 
@Override public void run() { 
System.out.println(Thread.currentThread().getName()+"重写"); 
}
 }
  • 实现Runnable接口,重写run()方法 ***

开启线程: Thread类做代理,调用Thread类中的start方法开启线程

优点:

避免了单继承的局限性

实现资源共享

class ThreadDemo implements Runnable{ 
@Override public void run() { 
System.out.println("实现Runnable接口"); 
}
 }

开启线程:

//Thread类做代理,调用Thread类中的start方法开启线程 
new Thread(new ThreadDemo(),"线程2").start();
  • 实现Callable接口,重写call()方法 (了解)

优点:可以有返回值,可以抛出异常

缺点:使用复杂

2.3 注意:

实现类也可以为内部类

public class InnerDemo04 { 
//静态内部类 
static class Inner1 implements Runnable {
 @Override public void run() { 
System.out.println("静态内部类");
 } 
} 
//成员内部类 
class Inner2 implements Runnable{ 
@Override public void run() { 
System.out.println("成员内部类");
 }
 }
 public static void main(String[] args) { 
new Thread(new Inner1(),"Inner1").start(); 
new Thread(new InnerDemo04().new Inner2(),"Inner2").start(); 
//局部内部类 
class Inner3 implements Runnable{ 
@Override public void run() { 
System.out.println("局部内部类"); 
} 
}
 new Thread(new Inner3(),"Inner3").start(); 
//匿名内部类 
new Thread(new Runnable() {
 @Override public void run() {
 System.out.println("匿名内部类");
 } 
},"匿名内部类").start();
 //lambda表达式 new Thread(()->{ System.out.println("lambda");} ,"Lambda").start(); } }

3、线程状态

3.1 五种状态

新生状态:new线程对象的时候,这个线程处于新生状态

就绪状态:调用start()方法,线程进入就绪状态,进入到就绪队列,进入就绪状态代表线程有能力执行,但是要等到cpu调用,分配时间片才能执行

运行状态:当前cpu调度,分配时间片给就绪状态的线程,当前线程执行

阻塞状态:sleep...

终止状态:线程结束

clipboard.png

3.2、sleep()方法:延迟

放大问题的可能性

模拟网络延迟

public class SleepDemo05 implements Runnable{ 
public static void main(String[] args) { 
new Thread(new SleepDemo05()).start(); 
} 
@Override public void run() { 
for (int i = 10; i!=0; i--) {
 try {
 //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) 
//此操作受到系统计时器和调度程序精度和准确性的影响。 
Thread.sleep(1000); 
} 
catch (InterruptedException e) {
 // TODO Auto-generated catch block e.printStackTrace(); 
} 
System.out.println("倒计时"+i+"秒");
 }
 System.out.println("游戏结束"); 
} 
}

3.3、yield()方法:礼让

如果当前线程调用yield方法,会直接进入到就绪状态

public class YieldDemo06 implements Runnable { 
public static void main(String[] args) {
 new Thread(new YieldDemo06(),"1").start(); 
new Thread(new YieldDemo06(),"2").start();
 } 
@Override public void run() { 
System.out.println(Thread.currentThread().getName()+"开始啦"); 
Thread.yield(); 
//礼让线程 
System.out.println(Thread.currentThread().getName()+"结束啦");
 }
 }

运行结果(进入就绪状态后,最终还是要看cpu的分配,并非按照顺序一定先执行哪一个线程)

2开始啦 
1开始啦
 2结束啦 
1结束啦

3.4、join()方法:插队

public class JoinDemo07 implements Runnable{
 public static void main(String[] args) {
 new Thread(new JoinDemo07(),"线程1").start();
 } 
@Override public void run() {
 System.out.println(Thread.currentThread().getName()+"启动"); 
Thread t=new Thread(new JumpAQueue(),"线程2"); 
t.start();
 try { 
t.join(); 
} catch (InterruptedException e) {
 e.printStackTrace(); 
} 
System.out.println(Thread.currentThread().getName()+"结束"); 
}
 } 
class JumpAQueue implements Runnable{ 
@Override public void run() { 
System.out.println(Thread.currentThread().getName()+"启动"); System.out.println(Thread.currentThread().getName()+"结束"); 
}
 }

运行结果

线程1启动 线程2启动 线程2结束 线程1结束

3.5、总结

  • 如何控制线程的终止:

调用stop(),destory(),已过时,不推荐

线程正常执行结束

添加标识控制

  • 进入线程就绪状态的几种情况:

start()方法

yield 礼让线程

线程之前切换

解除阻塞状态,线程进入到就绪状态

  • 进入线程阻塞状态的几种情况:

sleep方法

join方法

wait方法

IO操作

4、控制线程安全:加锁 使用关键字synchronized (

针对问题:多个线程同时操作同一份资源的时候,可能会发生线程不安全问题

  • 同步方法: 在方法上面加锁

同步静态方法

同步成员方法

/* * 
模拟案例:12306,3个人同时买100张票 * 方法上加锁,控制线程安全 
*/
 public class MethodSynchronized08 implements Runnable { 
// 100张票 
int tickets = 100;
 boolean flag=true; 
@Override public void run() { 
while (flag){ flag=syn();
 }
 } 
public synchronized boolean syn() { 
if(tickets<=0) return false;
 // 模拟购票延时 
try { 
Thread.sleep(200); 
} catch (InterruptedException e) { 
e.printStackTrace();
 } 
// 买票 
System.out.println(Thread.currentThread().getName() + "买了第" + tickets-- + "张票"); return true;
 } 
public static void main(String[] args) {
 //票为共享资源,因此需为同一对象 
MethodSynchronized08 ms=new MethodSynchronized08(); 
//开启线程 
new Thread(ms, "1号").start();
new Thread(ms, "2号").start();
new Thread(ms, "3号").start(); 
}
 }
  • 同步块: synchronized(){}

锁this,锁资源,锁类

/* *
 锁 块 控制线程安全 * 锁this就是锁对象,所对象会锁住这个对象中的所有成员(资源),如果只想锁住其中的某个资源,可以只锁这个资源
 */ 
public class Synchronized09 implements Runnable { 
// 100张票 
int tickets = 100;
 @Override public void run() { 
while (true) { 
synchronized (this) {
 if (tickets >= 1) {
 // 模拟购票延时 try { 
Thread.sleep(200); 
} catch (InterruptedException e) {
 e.printStackTrace(); 
} 
// 买票 
System.out.println(Thread.currentThread().getName() + "买了第" + tickets-- + "张票"); 
} 
}
 } 
}
 public static void main(String[] args) { 
// 票为共享资源,因此需为同一对象 
Synchronized09 ms = new Synchronized09();
 // 开启线程
 new Thread(ms, "1号").start(); ;
 new Thread(ms, "2号").start(); ; 
new Thread(ms, "3号").start(); ;
 }
 }

锁资源 一般就是指成员属性,锁一定要锁不变的内容,对象的地址永远不变,自定义的引用数据类型肯定能锁住

public class Synchronized10 implements Runnable { 
// 票 
Tickets tickets=new Tickets(); 
@Override public void run() {
 while (true) { 
//锁资源的地址,是对象肯定能锁住 synchronized (tickets) {
 if (tickets.num >= 1) { // 模拟购票延时 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace();
 } 
// 
买票 
System.out.println(Thread.currentThread().getName() + "买了第" + tickets.num-- + "张票");
 }
 } 
}
 } 
public static void main(String[] args) { 
// 票为共享资源,因此需为同一对象 
Synchronized09 ms = new Synchronized09(); 
// 开启线程
 new Thread(ms, "1号").start();
 new Thread(ms, "2号").start(); 
new Thread(ms, "3号").start();
 }
 }
 class Tickets { int num = 100; 
}

锁类的class对象,锁类,锁不变的东西

public class Synchronized11 implements Runnable { 
// 100张票
 int tickets = 100; 
boolean flag = true; 
@Override public void run() {
 while (true) { 
synchronized (Synchronized11.class) {
 if (tickets >= 1) {
 // 模拟购票延时
 try {
 Thread.sleep(200);
 } catch (InterruptedException e) { 
e.printStackTrace();
 } // 
买票 
System.out.println(Thread.currentThread().getName() + "买了第" + tickets-- + "张票"); 
}
 }
 } 
} 
public static void main(String[] args) { 
// 票为共享资源,因此需为同一对象 
Synchronized11 ms = new Synchronized11(); 
// 开启线程 
new Thread(ms, "1号").start();
 new Thread(ms, "2号").start(); 
new Thread(ms, "3号").start();
 } 
}

二、总结

1、 注意:

锁类,这个类的所有对象都被锁住了

锁this,值只锁住当前对象

锁的必须是不变的内容

锁的范围太大,效率低,锁的范围太小,容易锁不住

2、单例:懒汉式是线程不安全的

锁静态方法:

锁类锁静态方法都是锁类,在static方法中不能使用this,所以不能锁对象

double check 双重检查,效率更高 :

public class Demo01 {
 public static void main(String[] args) { 
new Thread(()->{ 
System.out.println(SingleTon.newInstance()); }).start();
 new Thread(()->{ 
System.out.println(SingleTon.newInstance()); }).start(); } 
}
 class SingleTon{
 //1.私有的静态的该类的应用 
private static SingleTon single=null; 
//2.私有的构造器 private SingleTon(){} 
//3.公共的静态的访问方式 
/*public synchronized static SingleTon newInstance(){ if(single==null){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } single=new SingleTon(); } return single; }*/ 
//双重检查双重锁 
public static SingleTon newInstance(){ 
if(single==null){
 try { 
Thread.sleep(200); 
} catch (InterruptedException e) { 
e.printStackTrace();
 }
 // synchronized (SingleTon.class) { 
if(single==null){ 
single=new SingleTon();
 } 
}
 } 
return single; 
} 
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351