多线程讲解和作业

多线程:

多线程的原理:

 

原理:多线程执行时候,在栈内存中,其实每一个执行线程都有一片所属的栈内存的空间,进行方法的压栈,和弹栈.
 
原理图:

 

 

多线程的创建:

三种方式:

第一种继承:

 1 package com.heima.duoxiancheng;
 2 
 3 //多线程的继承方式创建
 4 public class Demo01 extends Thread {
 5     //利用继承的特点
 6     //将线程名称传递进行设置
 7     public Demo01(String name) {
 8         super(name);
 9     }
10 
11     //重写run方法
12     @Override
13     public void run() {
14         for (int i = 0; i < 5; i++) {
15             //getName()方法来自与父亲类Thread
16             System.out.println(getName() + "正在执行:" + i);
17         }
18     }
19 
20     public static void main(String[] args) {
21         //创建类对象
22         Demo01 a = new Demo01("德玛");
23         //创建线程对象
24         Thread B = new Thread(a);
25         //开启线程
26         B.start();
27         //在主线程种执行
28         for (int j = 0; j < 5; j++) {
29             System.out.println("我叫做:" + j);
30         }
31     }
32 }

 第二种接口:

 

 1 package com.heima.duoxiancheng;
 2 //接口方式书写多线程
 3 public class Demo02 implements Runnable {
 4     //重写run方法
 5     @Override
 6     public void run() {
 7         for (int i = 0; i < 5; i++) {
 8             System.out.println(Thread.currentThread().getName() + "-" + i);
 9         }
10     }
11     public static void main(String[] args) {
12         //创建实现类对象
13         Demo02 a=new Demo02();
14         //创建线程对象
15         Thread thread = new Thread(a,"剑圣");
16         //开启线程
17         thread.start();
18         for (int j = 0; j < 5; j++) {
19             System.out.println("我是主线程:"+j);
20         }
21 
22     }
23 }

 

 

 

三.匿名内部类方式创建

 1 package com.heima.duoxiancheng;
 2 //匿名内部类
 3 public class Demo03 {
 4     public static void main(String[] args) {
 5         //创建Runnable对象
 6         Runnable runnable = new Runnable() {
 7             //重写run方法
 8             @Override
 9             public void run() {
10                 //创建多态对象
11                 for (int i = 0; i < 5; i++) {
12                     System.out.println("德玛:" + i);
13                 }
14             }
15         };
16       new Thread(runnable).start();
17         for (int j = 0; j < 5; j++) {
18             System.out.println(Thread.currentThread().getName()+" "+j);
19         }
20     }
21 }

 

优势:使用线程的匿名内部类方式,可以方便的实现每个线程执行不同的线程任务.

Thread和Runnable的区别:

 

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

 

总结:

 

实现Runnable接口比继承Thread类所具有的优势:

 

  1. 适合多个相同的程序代码的线程去共享同一个资源。

  2. 可以避免java中的单继承的局限性。

  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

  4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类.

扩充:在Java种每次程序运行至少启动两个线程,一个是main线程,一个是JVM.

Thread的构造方法:

 

  • public Thread():分配一个新的线程对象。

  • public Thread(String name):分配一个指定名字的新的线程对象。

  • public Thread(Runnable target):分配一个带有指定目标新的线程对象。

  • public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。

常用方法:

public String getName():获取当前线程名称。
public static Thread currentThread():返回对当前正在执行的线程对象的引用。
public void start():导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run():此线程要执行的任务在此处定义代码。
public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
注意:如果一个类继承Thread,则不适合资源的共享,但是实现了Runable接口的话,则很容易的实现资源共享.

 

 


 

 

实现Runnable接口比继承Threed类所具有的优势

 

1.适应多个相同的程序代码的线程去共享一个资源.
2.可以避免java中的单继承的局限性.
3.增加程序的健壮性,实现解耦操作,任务可以被多个线程共享,任务和线程独立.
4.线程池只能放入实现Runnable或Callable类线程,不能直接放入继承Thread的类
耦合性:类和类之间的相互影响的程度.
扩充:在java中,每次程序运行至少启动2个线程,一个是main线程,一个是垃圾收集线程,
因为每当使用Java命令执行一个类的时候,一个是垃圾收集线程,因为每当使用Java执行一个类
实际东辉启动一个jvm,每个JVM其实都是在操作系统启动一个进程.

 

线程安全:

定义:
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

 

实例题目:

 

 代码演示:

 
 1 package com.heima.duoxiancheng;
 2 //通过接口方式
 3 public class Demo04 implements Runnable{
 4     private int ticket=100;//设置票的个数
 5     Object jock=new Object();
 6     //重写run方法
 7     //执行买票操作
 8     @Override
 9     public void run() {
10         //窗口永远在开启
11         while (true){
12             //使用同步代码块解决去重问题
13             synchronized (jock){
14                 if(ticket>0) {//有票可以卖
15                     try {
16                         Thread.sleep(100);//模拟出票的时间
17                     } catch (InterruptedException e) {
18                         e.printStackTrace();
19                     }
20                     //获取当前线程对象的名字
21                     String name = Thread.currentThread().getName();
22                     System.out.println(name + "正在卖:" + ticket-- + "张。");
23                 }
24             }
25         }
26     }
27 
28     public static void main(String[] args) {
29         //创建线程任务的对象
30         Demo04 thread = new Demo04();
31         //创建窗口的对象
32         Thread thread1 = new Thread(thread,"窗口1");
33         Thread thread2 = new Thread(thread,"窗口2");
34         Thread thread3 = new Thread(thread,"窗口3");
35         thread1.start();
36         thread2.start();
37         thread3.start();
38     }
39 }

 

 


 

线程的同步:

 

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题

 

解决:

 

解决上诉问题多线程访问一个资源安全性问题,也就是解决重复的问题,java中提供了(synchronized)来解决

 

线程访问使用三种方式完成同步操作

 

1.同步代码快(synchronized)关键字可以用于方法的某个区块中表示区块资源的互斥访问.

 

格式:

 

 

 

synchronized(同步锁){
需要同步操作的代码
}

 

同步锁:

 

对象的同步锁只是一个概念,可以想象为在对象上标志记了一个锁

 

.锁对象(可以是任意数据对象)

 

.多个线程对象,要使用同一把锁.

 

注意:在任何时候,最多仍许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着(BLDCKED).

 

2.同步方法

 

3.锁机制

同步方法:

 

同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

 

 

 

public synchronized void method(){
可能会产生线程安全问题的代码
}

 

同步锁是谁:

 

对于非static方法,同步锁就是this.

 

对于static方法,我们使用当前方法所有类的字节代码对象(类名.class)
代码演示:
 1 package com.heima.biji;
 2 //同步方法
 3 public class Mythread04 implements Runnable{
 4         private int ticket = 100;//定义电影票的个数
 5         //重写run方法
 6         @Override
 7         public void run() {
 8             //每个窗口买票的过程
 9             //窗口永远在开启
10             while (true){
11                 sellTicket();
12             }
13         }
14         public synchronized void sellTicket(){
15             if(ticket>0){
16                 try {
17                     Thread.sleep(100);
18                 } catch (InterruptedException e) {
19                     e.printStackTrace();
20                 }
21                 //获取当前线程对象的名字
22                 String name = Thread.currentThread().getName();
23                 System.out.println(name + "正在买:" + ticket-- + "");
24             }
25         }
26     }

 

 

lock锁:

 

java.util.concurrent.loks.Lock机制提供了比synchronized代码块,和synchronized方法

 

Lock锁也称同步锁,加锁与释放锁方法化了,如下:

public void lock():加同步锁。
 lock他是一个接口,他只能new 实现类ReentrantLock
public void unlock():释放同步锁。

 

代码快:

 

 1 package com.heima.biji;
 2 import java.lang.invoke.VarHandle;
 3 import java.util.concurrent.locks.Lock;
 4 import java.util.concurrent.locks.ReentrantLock;
 5 
 6 //Lock锁
 7 public class Mythread05 implements Runnable {
 8     //设置票数
 9     private int ticket = 100;
10     Lock lock = new ReentrantLock();
11 
12     //执行买票操作
13     @Override
14     public void run() {
15         while (true) {
16             lock.lock();//加同步锁
17             if (ticket > 0) {//有票可以买
18                 //每个窗口买票的操作
19                 //窗口 永远开启
20                 try {
21                     Thread.sleep(100);
22                 } catch (InterruptedException e) {
23                     e.printStackTrace();
24                 }
25                 //获取当前线程对象的名字
26                 String name = Thread.currentThread().getName();
27                 System.out.println(name + "正在买:" + ticket-- + "");
28             }
29             lock.unlock();//释放同步锁
30         }
31     }
32 }

 

 

 

线程状态概述:

 

当线程被创建并启动后,他既不是一启就进入执行状态,也不是一直处于执行状态:

 

在线程生命周期中有6种状态.

 

 

 

线程状态
导致方式条件
NEW(新建)
线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行)
线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
Blocked(锁阻塞)
当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待)
一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。通过wait()方法进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
TimedWaiting(计时等待)
同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。

 

   Teminated(被终止)       :        因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

 

Timed Waiting(计时等待):

 

  • Timed Waiting在API中的描述为:一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态。单独的去理解这句话,真是玄之又玄,其实我们在之前的操作中已经接触过这个状态了,在哪里呢?

 

BLOCKED(锁阻塞):

图解:

 

Waiting(无限等待):

图解:

 

 

 

posted on 2019-04-01 11:30  风一般的男子·小亮  阅读(255)  评论(0编辑  收藏  举报

导航