学习Java多线程这一篇就够了

您所在的位置:网站首页 多线程的通信 学习Java多线程这一篇就够了

学习Java多线程这一篇就够了

#学习Java多线程这一篇就够了| 来源: 网络整理| 查看: 265

目录

进程与线程

进程基本概念及理解

线程基本概念及理解

进程线程对比

创建进程

继承Thread类创建多线程

实现Runnable接口创建多线程

实现Callable接口创建多线程

Thread类与Runnable接口实现多线程对比

线程状态

线程调度

线程的优先级

线程休眠

线程插队

线程让步

线程中断

守护线程

线程同步

同步代码块

同步代码块

同步方法

死锁问题

Lock锁

进程与线程

多线程是提升程序性能重要方式,也是java中一项重要的技术。多线程是指一个应用程序中有多条并发执行的线索,每条线索都是一个线程,线程之间可以可以交替执行,彼此可以通信。

进程基本概念及理解

程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。

进程则是一个动态的概念,进程则是执行程序的一次执行过程,是系统进行资源分配和调度的基本单位。

程序就是保存在磁盘上,编译好的二进制文件,不占用系统资源进程存在于内存中,占用系统资源一个单核的CPU同一时刻只能处理一个进程

在单核CPU背景下,平时我们在一台计算机上,可以同时打游戏,听音乐,语音通话可以同时进行,感觉是有多个进程在运行,但实际上是计算机系统采用了多到程序设计技术,就是在内存管控下,多个进程之间相互穿插执行。

采用多到程序设计的系统会把CPU周期划分为多个长度相同的时间片,在每个时间片内只能处理一个进程,也就是说内存里面的多个进程轮流交替使用CPU。而我们产生错觉的原因是,CPU的时间片非常小,我们难以感受到其中差异。因此在宏观上,可以认为是计算机可以并发执行多个进程。

线程基本概念及理解

每个运行的程序就是以一个进程,一个进程里面可以有多个执行单元同时执行,这些执行单元就是线程,每个进程至少有一个线程。线程是CPU调度和执行的的单位。

多线程和单线程的区别:

多线程看起是同时执行的,他们和进程是一样的,由CPU轮流执行,只是CPU执行速度很快,几乎感觉不到。

真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉

进程线程对比 进程是系统进行资源分配和调度的基本单位,线程是CPU调度和执行的的单位。一个进程里面至少包含一个多线程,可以包含多个。

关于多线程理解:

线程就是独立的执行路径;在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;main() 称之为主线程,为系统的入口,用于执行整个程序;在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的。对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;线程会带来额外的开销,如cpu调度时间,并发控制开销每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

创建进程

三种创建进程方式:

继承Thread类创建多线程

通过继承Thread类,重写类中run方法,即可实现多线程。

start() 启动新线程,之后Java虚拟机自动调用run方法。

package Example1; // 继承Thread类创建多线程 public class Test1 { public static void main(String[] args) { Mythread mythread = new Mythread(); mythread.start(); while(true) { System.out.println("main()方法在运行"); } } } class Mythread extends Thread { public void run() { while(true) { System.out.println("MyThread类的run方法在运行"); } } }

运行结果:

Mythread.start()启动新的线程,和之前main()线程里的代码同时执行。

实现Runnable接口创建多线程

Thread类提供了一个构造方法,Thread(Runnable target) ,参数是一个接口,它只有一个run方法。

通过这个构造方法创造Thread对象时,需要传递一个Runnable实现接口对象。通过Thread的对象调用start()方法,来执行run()。

这样一来,调用新线程任务就交给Thread执行,原本的类只需要实现Runnable接口即可。可以避免Java单继承的问题。

package Example2; public class Test2 { public static void main(String[] args) { Mythread mythread = new Mythread(); Thread thread = new Thread(mythread); thread.start(); while(true) { System.out.println("main()方法在运行"); } } } // Mythread实现Runnable()接口,并且重写run()方法 class Mythread implements Runnable { public void run() { while(true) { System.out.println("MyThread类的run方法在运行"); } } }

运行结果:

实现Callable接口创建多线程

前两种创建进程方法存在缺点,无法从run()方法获取返回值。

实现Callable接口可以满足创建多线程和获取返回值的要求。

package Example3; import java.util.concurrent.*; // 实现Callable创建多线程 public class Test3 { public static void main(String[] args) throws InterruptedException,ExecutionException{ // 创建实现Callable接口的实例对象 Mythread mythread = new Mythread(); // 使用FutureTask封装Mythread类 FutureTask ft = new FutureTask(mythread); // 使用Thread(Runnable target,String name)创建线程对象 Thread thread = new Thread(ft,"thread"); // 启动新线程 thread.start(); // currentThread().getName() 当前线程名字 get() 返回管理值 System.out.println(Thread.currentThread().getName()+"的返回结果"+ft.get()); int a=0; while(a++0) { // 调用Thread类种的currentThread().get()获取当前执行线程的名字 Thread th = Thread.currentThread(); //返回一个对象 String name = th.getName(); System.out.println(name+"正在发售第" + tickets-- + "张票"); } } } package Example5; public class Test5 { public static void main(String[] args) { TicketWindow tk = new TicketWindow(); new Thread(tk,"窗口1").start(); new Thread(tk,"窗口2").start(); new Thread(tk,"窗口3").start(); new Thread(tk,"窗口4").start(); } } class TicketWindow implements Runnable { private int tickets=100; public void run () { while(tickets>0) { Thread th =Thread.currentThread(); String name = th.getName(); System.out.println(name + "正在发售第" + tickets-- + "张票"); } } }

综合考虑,建议在创建多线陈的时候使用实现Runnable方式创建多线程。

线程状态

线程的基本状态:新建,运行,阻塞,等待,中止

线程调度

线程调度有两种模型:分时调度模型和抢占式调度模型

分时调度模型:所有线程轮流获得CPU的使用权,就是平均主义抢占式调度模型:根据线程优先级获得CPU使用权,优先级相同则线程随机获得CPU使用权

Java虚拟机默认采用抢占式调度模型

线程的优先级

优先级高的的线程获得CPU使用权的机会就越大,优先级低的线程获得CPU使用机会越小。

线程的优先级用1-10,数字越大,优先级越高。Thread类中提供了三个静态常量表示线程的优先级。

static int MAX_PRIORITY:表示线程最高优先级,表示10;

static int MIN_PRIORITY :表示线程最低级,表示1;

static int NORM_PRIORITY:表示线程默认优先级,表示5;

package Example6; public class Test6 { public static void main(String[] args) { Thread mp = new Thread(new MaxPriority(),"优先级较高线程"); Thread np = new Thread(new MinPriority(),"优先级较低线程"); mp.setPriority(Thread.MAX_PRIORITY); np.setPriority(Thread.MIN_PRIORITY); mp.start(); np.start(); } } class MaxPriority implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+"正在输出"+i); } } } class MinPriority implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+"正在输出"+i); } } }

其实,即使设置了线程的优先级,一样无法确保这个线程一定先执行,因为它有很大的随机性。它并无法控制执行哪个线程,因为线程的执行,是抢占资源后才能执行的操作,而抢点资源时,最多是给于线程优先级较高的线程一点机会而已,能不能抓住可是不一定的。。

线程休眠

是指让当前线程暂停执行,从运行状态进入阻塞状态,将CPU资源让给其它线程的调度方式

package Example7; public class Test7 { public static void main(String[] args) throws Exception { new Thread(new SleepThread()).start(); for(int i=1;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3