Java 多线程

一、线程概述

进程直译:正在进行中的程序

线程

线程就是进程中一个负责程序执行的控制单元(执行路径) 一个进程中可以有多个执行路径,称为多线程。开启多个线程是为了同时运行多部分代码。 一个进程中至少有一个线程。每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。

二、多线程好处与弊端

好处:解决了多部分同时运行的问题

弊端:线程太多会导致效率降低

其实应用程序的执行都是 cpu 在做着快速切换完成的。这个切换是随机的。

三、JVM 中多线程的解析

JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。 1、执行main函数的线程 该线程的任务代码都定义在main函数中。 2、负责垃圾回收的线程

四、线程的创建方式-Thread类

创建新执行线程有两种方法:

第一种方法是将类声明为 Thread 的子类。该子类重写 Thread 的 run 方法

class Demo extend Thread{

private String name;

Demo(name){

this.name = name;

}

public void run(){

this.show();

}

public void show(){

for(int x = 0;x<10;x++){

System.out.println(name+"...x="+x);

}

}

}

class ThreadDemo{

public static void main(){

//创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行

//而运行的指定代码就是这个执行路径的任务

//jvm创建的主线程的任务都定义在了主函数中。

//而自定义的线程的任务在哪呢?

//Thread类用于描述线程,线程是需要任务的,所以Thread类也是对任务的描述

//这恶搞任务就是通过Tnread的run方法体现,也就是说run方法就是封装自定义线程运行任务的函数。

//run方法中定义的就是线程要运行的任务代码

//开启线程是为了运行指定代码,所以只有继承Thread类,并覆写run方法

//将运行的代码定义在run方法中即可。

Demo d1 = new Demo("旺财");

Demo d2 = new Demo("xiaoqiang");

d1.start();//开启线程后,jvm会自动调用该线程的run方法

d2.start();//不用自己手动调用run方法

}

}

第二种方法是实现 Runnable 接口

class Demo implements Runnable{//准备扩展Deno类的功能,让其中的内容可以作为线程的任务执行,通过接口的形式完成

private String name;

Demo(name){

this.name = name;

}

public void run(){

this.show();

}

public void show(){

for(int x = 0;x<10;x++){

System.out.println(name+"...x="+x);

}

}

}

class ThreadDemo{

public static void main(){

Demo d1 = new Demo();//这时候不是线程对象,不能调用start

Thread t1 = new Thread(d1);//线程对象

Thread t2 = new Thread(d1);

t1.start();

t2.start();

}

}

第二种方法的好处:

  1. 将线程的任务从线程的子类中分离出来,进行了单独的封装(按照面向对象的思想将任务封装成对象)
  2. 避免了 java 单继承的局限性

所以常见线程的第二种方式比较常用。

五、Thread 类中的方法 – 线程名称

可以通过 Thread 的 getName 获取现场的名称 Thread-编号(从0开始)

class Demo extend Thread{

private String name;

Demo(name){

this.name = name;

}

public void run(){

this.show();

}

public void show(){

for(int x = 0;x<10;x++){

//线程以创建,名字就有了

System.out.println(name+"...x="+x+"ThreadName="+this.getName());

//获取当前运行线程的名字

System.out.println(name+"...x="+x+"ThreadName="+Thread.currentThread().getName());

}

}

}

六、多线程运行内存图解

Java 多线程

七、线程的四种状态

Java 多线程

cpu 的执行资格:可以被 cpu 处理,在处理队列中排队。

cpu 的执行权:正在被 cpu 处理。

运行状态的线程具备 cpu 的执行资格和 cpu 的执行权 ,临时阻塞状态的线程具备 cpu 的执行资格,但不具备 cpu 的执行权 冻结状态的线程,不具备 cpu 的执行资格和 cpu 的执行权。

八、卖票示例

class Ticket implements Runnable{

private int num = 100;

public void run(){

while(true){

if(num>0){

System.out.println(Thread.currentThread().getName()+"...sale..."+num--)

}

}

}

}

class TicketDemo{

public static void main(String[] args){

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

Thread t4 = new Thread(t);

t1.start();

t2.start();

t3.start();

t4.start();

}

}

九、多线程安全问题

class Ticket implements Runnable{

private int num = 100;

public void run(){

while(true){

if(num>0){

try{//由于线程的安全问题,可能会导致负数票的出现

Thread.sleep(10);

System.out.println(Thread.currentThread().getName()+"...sale..."+num--);

}catch{}

}

}

}

}

class TicketDemo{

public static void main(String[] args){

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

Thread t4 = new Thread(t);

t1.start();

t2.start();

t3.start();

t4.start();

}

}

线程安全问题产生的原因

  1. 多个线程在操作共享的数据。
  2. 操作共享数据的代码有多条。

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。

十、解决多线程问题-同步代码块

解决思路:就是将多条操作共享数据的线程封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。

在 java 中同步代码块就可以解决这个问题,同步代码块的格式:

synchronized(对象){

需要被同步的代码;

}

修改代码如下:

class Ticket implements Runnable{

private int num = 100;

Object obj = new Object();//创建一个对象为同步代码块使用

public void run(){

while(true){

synchronized(obj){//同步代码块

if(num>0){

try{

System.out.println(Thread.currentThread().getName()+"...sale..."+num--);

}catch{}

}

}

}

}

}

class TicketDemo{

public static void main(String[] args){

Ticket t = new Ticket();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

Thread t3 = new Thread(t);

Thread t4 = new Thread(t);

t1.start();

t2.start();

t3.start();

t4.start();

}

}

同步代码块的好处与弊端

  • 同步的好处:解决了线程安全问题
  • 同步的弊端:相对以前降低了效率,因为同步外的线程都会判断同步锁。
  • 同步的前提:必须有多个线程必须使用同一个锁。

十一、解决多线程问题-同步函数

class Back{

private int sum;

private Object obj = new Object();

public void add(int num){

synchronized(obj){//同步代码块

sum = sum+num;

try{Thread.sleep(10)}catch(InterruptedExpection e){}

System.out.println("sum="+sum);

}

}

//同步的第二种表现形式

public void synchronized add(int num){//同步函数 (只需要用synchronized关键字修饰即可,不用使用锁)

sum = sum+num;

try{Thread.sleep(10)}catch(InterruptedExpection e){}

System.out.println("sum="+sum);

}

}

class Cus implements Runnable{

private Bank b = new Bank();

public void run(){

for(int x=0;x<3;x++){

b.add(100);

}

}

}

使用同步代码块时候的锁是自己 new 的一个对象,那么同步函数的锁是什么呢?(this)

建议使用同步代码块

静态同步函数用的锁就不是this了。当前的字节码对象 (this.getClass()/类名.class)

十二、单例模式涉及的多线程问题

//饿汉式(不存在线程安全问题)

class Single{

private static final Single s = new Single();

private Single(){}

public static Single getInstance(){

return this.s;

}

}

//懒汉式(存在安全问题需要解决)

class Single{

private static Single s = null;

private Single(){}

public static Single getInstance(){

if(s==null){

s = new Single();

}

return this.s;

}

//解决线程安全

public static Single getInstance(){

if(s==null){

synchronized(Single.class/this.getClass()){

if(s==null){

s = new Single();

}

}

}

return this.s;

}

}

十三、死锁

死锁的出现之一:同步的嵌套

class Test implements Runnable{

private boolean flag;

Test(boolean flag){

this.flag = flag;

}

public void run(){

if(flag){

synchronized(MyLock.locka){

System.out.println("if locka...");

synchronized(MyLock.lockb){

System.out.println("if lockb...");

}

}

}else{

synchronized(MyLock.lockb){

System.out.println("else lockb...");

synchronized(MyLock.locka){

System.out.println("else locka...");

}

}

}

}

}

class MyLock{

public static final Object locka = new Object();

public static final Object lockb = new Object();

}

class DeadLockTest{

public static void main(){

Test a = new Test(true);

Test b = new Test(false);

Thread t1 = new Thread(a);

Thread t2 = new Thread(b);

t1.start();

t2.start();

}

}

以上是 Java 多线程 的全部内容, 来源链接: utcz.com/p/233535.html

回到顶部