ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

多线程

2022-04-20 13:33:11  阅读:146  来源: 互联网

标签:Thread void 死锁 boolean 线程 多线程 public


多线程

一.前言

​ 掌握程序的概念,创建方式和常用方法,掌握线程的同步方法解决并发问题,掌握死锁的处理方式,了解线程的生命周期

二.概述

1.进程

​ 电脑中会有很多单独运行的程序,每个程序有一个独立的进程,而进程之间是相互独立存在的。

2.线程

​ 进程想要执行任务就需要依赖线程。进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。

  • 串行:

    ​ 所谓串行,其实是相对于单条线程来执行多个任务来说,依次排队执行,它们在时间上是不可能发生重叠的。

  • 并行:

    ​ 执行多个任务,开启多条线程,多个任务同时进行,这里是严格意义上的,在同一时刻发生的,并行在时间上是重叠的。

三.创建方式

1.继承 Thread 类

​ 创建 java.lang.Thread 类的子类,重写该类的 run方法。

构造方法:

Thread()
创建已继承Thread类的线程对象
Thread(String name)
分配一个新的 Thread对象,并且给线程命名


2.Runnable 接口

​ 创建 java.lang.Runnable接 口的实现类,实现接口中的 run 方法。

构造方法:

Thread(Runnable target)
创建一个Thread类对象,放入继承Runnable类的对象
Thread(Runnable target,String name)
创建一个Thread类对象,放入继承Runnable类的对象,并且给线程命名

3.实例化举例

  • 创建Thread 类线程对象例:
//演示多线程后台执行操作
public class TestThread1 extends Thread{
	
	@Override
	public void run() {
		// run方法线程体
		for (int i = 0; i < 10; i++) {
			System.out.println("自己创建的线程-----" + i);
		}
	}
	
    public static void main(String[] args) {
        //创建一个线程对象
        TestThread1 thread1 = new TestThread1();
		//调用start方法
        thread1.start();
        //main线程,主线程
        for (int i = 0; i < 200; i++) {
            System.out.println("main主线程++++"+i);
        }
    }
}  //注意:线程开启不一定立即执行,由cpu调度执行。
  • Runnable接口实现自定义线程类例:
public class TestRunnable implements Runnable{
	// 实现自定义线程类,实现Runnable中的run方法
	@Override
	public void run() {	
		for (int i = 0; i < 10; i++) {
			System.out.println("当前线程为:" + Thread.currentThread());
		}
		
	}
	
	public static void main(String[] args) {
		Thread t1 = new Thread(new TestRunnable());
		Thread t2 = new Thread(new TestRunnable());
		t1.start();
		t2.start();	
	}
}

四,常用方法

1.静态方法:

static Thread currentThread():
	返回当前正在执行的线程对象
static boolean interrupted():
	查询当前线程是否已经中断
static void sleep(long millis):
	在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

2.获取方法:

long getId():
	返回该线程的唯一标识符。
int getPriority():
	返回线程的优先级。
Thread.State getState():
	返回该线程的状态。

3.其他方法:

void start(): 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

void join(): 等待该线程终止。

void join(long millis): 等待该线程终止的时间最长为 millis 毫秒。

void interrupt(): 中断线程。

boolean isInterrupted(): 测试线程是否已经中断。

boolean isAlive(): 测试线程是否处于活动状态。

boolean isDaemon(): 测试该线程是否为守护线程。即后台线程

void setPriority(int newPriority): 更改线程的优先级。
    static int	MAX_PRIORITY = 10;
	线程可以拥有的最大优先级。
	static int	MIN_PRIORITY = 1;
	线程可以拥有的最小优先级。
	static int	NORM_PRIORITY = 5;
	分配给线程的默认优先级。

五,同步方法(synchronized关键字)

​ synchronized 关键字是 Java 编程中,为解决并发问题,线程同步的常用手段之一。

1.作用

  • 确保线程互斥的访问同步代,锁自动释放,多个线程操作同个代码块或函数必须排队获得锁。
  • 保证共享变量的修改能够及时可见,获得锁的线程操作完毕后会将所数据刷新到共享内存区。
  • 不解决重排序,但保证有序性。

2.用法

  • 非静态方法的同步;
  • 静态方法的同步;
  • 代码块同步;

3.对象锁

方法对象锁

 public synchronized void test(){
        // TODO
  }    

代码块队形锁:

public void test(){
    synchronized (this) {
        // TODO
   }
}

4.类锁

方法类锁

 public static synchronized void test(){
        // TODO
  }

代码块类锁

   public static void test(){
        synchronized (TestSynchronized.class) {
            // TODO
        }
    }

六、ReentrantLock

​ 实现线程同步,保证线程安全。jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock。但ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。

1.ReentrantLockd的构造方法

// 创建一个 ReentrantLock ,默认是“非公平锁”。
ReentrantLock()

// 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair)

2.常用方法

// 获取锁。
void lock()
    
// 试图释放此锁。
void unlock()

// 查询当前线程保持此锁的次数。
int getHoldCount()

// 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
protected Thread getOwner()

// 返回一个 collection,它包含可能正等待获取此锁的线程。
protected Collection<Thread> getQueuedThreads()

// 返回正等待获取此锁的线程估计数。
int getQueueLength()

// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected Collection<Thread> getWaitingThreads(Condition condition)

// 返回等待与此锁相关的给定条件的线程估计数。
int getWaitQueueLength(Condition condition)

// 查询给定线程是否正在等待获取此锁。
boolean hasQueuedThread(Thread thread)

// 查询是否有些线程正在等待获取此锁。
boolean hasQueuedThreads()

// 查询是否有些线程正在等待与此锁有关的给定条件。
boolean hasWaiters(Condition condition)

// 如果是“公平锁”返回true,否则返回false。
boolean isFair()
    
// 查询当前线程是否保持此锁。
boolean isHeldByCurrentThread()

// 查询此锁是否由任意线程保持。
boolean isLocked()

// 如果当前线程未被中断,则获取锁。
void lockInterruptibly()

// 返回用来与此 Lock 实例一起使用的 Condition 实例。
Condition newCondition()

// 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
boolean tryLock()

// 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
boolean tryLock(long timeout, TimeUnit unit)

3.实例化使用

ReentrantLock lock = new ReentrantLock(); 
lock.lock();
try {
	// TODO
} finally {
    lock.unlock(); //保证这个锁一定会释放
}

4.公平锁与非公平锁

 // 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair)

​ 公平锁,锁有利于授予访问最长等待的线程;

​ 非公平锁,该锁不保证任何特定的访问顺序;

七.死锁

1.死锁的定义

​ 死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

2.死锁实例化示意

public class DeadLock implements Runnable{
    
    private static Object obj1 = new Object();
    private static Object obj2 = new Object();
    private boolean flag;
    
    public DeadLock(boolean flag){
        this.flag = flag;
    }
    
    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName() + "运行");
        
        if(flag){
            synchronized(obj1){
                System.out.println(Thread.currentThread().getName() + "已经锁住obj1");
                try {  
                    Thread.sleep(1000);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                synchronized(obj2){
                    // 执行不到这里
                    System.out.println("1秒钟后,"+Thread.currentThread().getName()
                                + "锁住obj2");
                }
            }
        }else{
            synchronized(obj2){
                System.out.println(Thread.currentThread().getName() + "已经锁住obj2");
                try {  
                    Thread.sleep(1000);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                synchronized(obj1){
                    // 执行不到这里
                    System.out.println("1秒钟后,"+Thread.currentThread().getName()
                                + "锁住obj1");
                }
            }
        }
    }

}

3.如何避免死锁

在有些情况下死锁是可以避免的。下面介绍三种用于避免死锁的技术:

  • 加锁顺序(线程按照一定的顺序加锁)
  • 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
  • 死锁检测

加锁顺序:

​ 当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生

加锁时限:

​ 这种机制存在一个问题,在Java中不能对synchronized同步块设置超时时间。你需要创建一个自定义锁,或使用Java5中java.util.concurrent包下的工具。

死锁检测:

​ JDK提供了两种方式来给我们检测:

​ JconsoleJDK自带的图形化界面工具,使用JDK给我们的的工具JConsole。

​ Jstack是JDK自带的命令行工具,主要用于线程Dump分析。

九,线程的生命周期

1.新建状态(New)

​ 当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

2 .就绪状态(Runnable)

​ 也被称为“可执行状态”。当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

3.运行状态(Running)

​ 当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

4.阻塞状态(Blocked)

​ 处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

5.死亡状态(Dead)

​ 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

标签:Thread,void,死锁,boolean,线程,多线程,public
来源: https://www.cnblogs.com/simashun/p/16169449.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有