java 线程的插队运行_Java实战开发篇-11 多线程

多线程

一、多线程中的几个概念

1.程序:静态的代码

2.进程:正在运行的一个程序 正在使用的QQ,Android Studio。进程用于管理所有的资源,不进行实际的任务

3.线程:完成具体任务,QQ运行起来就是线程(一个进程里面可以有多个线程)。运行QQ,聊天、视频、QQ游戏同时运行,这就是一个个线程

4.主线程:Java里面,main方法里面的代码就在主线程中运行。在手机里面,我们看到的主界面,就是一个主线程

5.子线程:除了主线程之外的线程

二、为什么使用多线程

在主线程里面,任务的执行是从上至下的,如果其中一个任务需要耗费大量时间。那么这个任务后面的任务就必须等这个任务结束后才能被执行,就会形成阻塞。这个时候就需要将这个任务放在另一个线程里面去执行(子线程)

*注:不管是主线程还是子线程都有自己独立的执行路径

三、如何开启一个线程

1.写一个类继承于Thread

步骤:

(1)创建类继承于Thread,具体执行的任务放在run()里面

(2)创建类的对象

(3)调用start()方法执行

注*线程的执行是通过抢占时间片来获取执行机会的,时间片是由操作系统来分配的

所以有多个线程的时候,每次执行的结果可能不一样

class TestThread extends Thread{

//1.创建一个类继承于Thread

//可以通过重写构造方法给子线程命名

public TestThread(@NonNull String name) {

super(name);

}

@Override

//子类必须实现父类的run方法,这个线程执行的任务在run方法里面

public void run() {

System.out.println(getName());

//也可以用Thread.currentThread(),获取当前线程的名字

System.out.println("Hello World");

}

}

public class MyClass {

public static void main(String[] args){

//2.创建具体的对象

TestThread testThread = new TestThread("子线程");//给子线程命名

//3.启动线程,不调用start无法启动线程

testThread.start();

}

}

public static void testRunnable(){

//2.创建具体对象

TestRunnable testRunnable = new TestRunnable();

//3.创建一个Thread对象 让这个线程去执行testRunnable的任务

Thread thread = new Thread(testRunnable);

thread.start();

}

}

2.写一个类实现Runnable接口

步骤:

(1)创建一个类实现Runnable接口,但它并不能分配线程

(2)创建一个该类的对象

(3)创建Thread类的对象来创建线程

(4)调用start方法开启线程

class TestRunnable implements Runnable{

//1.创建一个类实现Runnable方法

//这个类不能开启线程,也需要通过Thread来开启

@Override

public void run() {

System.out.println("Hello World");

}

}

public class MyClass {

public static void main(String[] args){

//2.创建具体对象

TestRunnable testRunnable = new TestRunnable();

//3.创建一个Thread对象 让这个线程去执行testRunnable的任务

Thread thread = new Thread(testRunnable);

thread.start();

}

}

3.两种启动方式的对比

第一种创建方法简单一些,但是无法实现多继承

第二种灵活性更强,因为接口可以实现多继承

四、线程的生命周期

线程的5种形态

new创建状态->start就绪状态->run死亡状态

运行状态中,可能遇到阻塞状态

1.创建状态

new Thread()

2.就绪状态

(1)调用start()

(2)阻塞条件结束

(3)正在运行的线程时间片被其他线程所抢夺

3.运行状态

从就绪状态到运行状态是由操作系统进行,外部无法干预

4.死亡状态

(1)run方法结束

(2)手动让线程暂停 stop(不建议使用,通过其他方式暂停)

5.阻塞状态

阻塞状态分为3种,同步阻塞synchronized,等待阻塞wait,其他阻塞sleep,join

五、如何让一个线程结束

(1)使用stop()方法;(此方法不建议使用)

(2)写一个变量来标识线程结束

class TestThread extends Thread{

boolean stop = true;

@Override

public void run() {

while (stop) {

System.out.println("子线程");

}

}

public void terminated(){

stop = false;

}//写一个终止方法

}

public class MyClass {

public static void main(String[] args){

TestThread t = new TestThread();

t.start();

for(int i = 0;i<20;i++){

if(i==10){

t.terminated();

}

}

}

}

六、线程礼让和线程插队

线程礼让:yield()

线程插队:join()

礼让的线程会直接进入就绪状态,如果这个线程再次获得时间片,它还会执行,所以可能礼让失败

TestRunnable testRunnable = new TestRunnable();

Thread t1 = new Thread(testRunnable,"子线程1");

t1.start();

for(int i = 0;i<100;i++){

System.out.println("主线程");

if(i == 20){

Thread.yield();

}

}

public class MyClass {

public static void main(String[] args){

TestThread t = new TestThread();

t.start();

}

}

插队同理,插队后的线程执行完后再执行原线程

七、多线程的利弊

1.优点

(1)提高执行的效率

(2)不会阻塞主线程

2.缺点

(1)多个线程操作同一个资源时,有可能会出错

class BuyTickets extends Thread{

static int total = 10;

@Override

public void run() {

for(int i = 1;i<11;i++){

if (total == 0) {

stop();

}

}

total--;

System.out.println("第"+(10-total)+"张票购成功");

}

}

}

public class MyClass {

public static void main(String[] args){

BuyTickets Passenger1 = new BuyTickets();

BuyTickets Passenger2 = new BuyTickets();

BuyTickets Passenger3 = new BuyTickets();

Passenger1.start();

Passenger2.start();

Passenger3.start();

}

}

3.克服缺点的办法

(1)Lock锁,代码块必须使用同一把锁

(2)2.synchronized锁

class BuyTickets extends Thread{

Object object = new Object();//创建一个临时对象

static int total = 10;

@Override

public void run() {

for(int i = 1;i<11;i++){

synchronized (object) {

if (total == 0) {

stop();

}

}

total--;

System.out.println("第"+(10-total)+"张票购成功");

}

}

}

public class MyClass {

public static void main(String[] args){

BuyTickets Passenger1 = new BuyTickets();

BuyTickets Passenger2 = new BuyTickets();

BuyTickets Passenger3 = new BuyTickets();

Passenger1.start();

Passenger2.start();

Passenger3.start();

}

}

*注:锁的对象必须相同,每一个对象都维护一把锁

不管是锁代码块还是锁方法,尽量让锁的范围变小

八、线程间的通信

1.实现线程间通信的三个方法

(1)wait()让某个线程等待

(2)notify()唤醒某个线程

(3)notifyAll()唤醒所有线程

*注:这三个方法必须由同步监视器(必须被Lock或synchronized包装的代码块)来调用

public class MyClass {

static intersection section = new intersection();

public static void main(String[] args){

new Thread(new Runnable() {

@Override

public void run() {

section.printnum();

}

}).start();

new Thread(new Runnable() {

@Override

public void run() {

section.printlet();

}

}).start();

}

}//匿名对象和匿名内部类快速创建对象和调用方法

class intersection{

int number = 1;

char letter = 'a';

int state = 1;//通过变化state的值来改变线程

public synchronized void printnum(){

while(true){

if(state != 1){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(number);

number++;

if(number == 27){

break;

}

state = 2;

this.notify();

}

}

public synchronized void printlet(){

while(true){

if(state != 2){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println(letter);

letter++;

if(letter == ('z'+1)){

break;

}

state = 1;

this.notify();

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值