多线程基础知识

本文介绍了多线程的基本概念,包括程序、进程和线程的区别。讲解了多线程的创建方式,如继承Thread类、实现Runnable接口、使用Callable和Future以及线程池。接着阐述了多线程的常用方法,如start()、run()、join()等。此外,还讨论了多线程生命周期中的安全问题,如线程不确定性导致的结果不稳定性、数据完整性问题,并提出了同步代码块、同步方法和Lock锁等解决方案。最后提到了线程的死锁现象及线程间的通信示例。

基本概念

  1. 程序: 为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象;
  2. 进程: 是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程:有它自身的产生、存在和消亡的过程----生命周期;
  3. 线程 : 进程可以进一步细化为线程,是程序内部的一条执行路径,一个程序可以有多条执行路径;

程序是静态的,进程是动态的;

进程作为资源分配单位,系统在运行时会为每个进程分配不同的内存区域;

线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器;

一个进程中的多个线程共享相同的内存单元/内存地址空间–它们从同一堆中分配对象,可以访问相同的变量和对象,这就是线程间的通信更加的简便、高效,但是多线程操作共享的系统资源可能带来安全隐患;

多线程的创建方式

面试题:创建多线程的方式有几种?
答:四种;
1). 继承Thread类的方式创建线程;
2). 实现Runnable接口创建线程;
3). 使用Callable和Future创建线程;
4). 使用线程池例如用Executor框架;

1.继承Thread类的方式创建线程:

public class Main01 {

    public static void main(String[] args) {
        //给主线程命名:Thread.currentThread()是获取当前线程
        Thread.currentThread().setName("主线程");
        //打印
        System.out.println(Thread.currentThread().getName()+"线程执行了");
        //创建一个线程
        MyThread myThread = new MyThread();
        //启动线程
        myThread.start();
    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程执行了");
    }
}
//输出
 	主线程线程执行了
	Thread-0线程执行了

2.实现Runnable接口的方式创建线程:

public class Main02 {

    public static void main(String[] args) {
        //给main线程命名
        Thread.currentThread().setName("主线程");
        //打印
        System.out.println(Thread.currentThread().getName()+"执行了");

        //创建线程
        MyRunnable myRunnable = new MyRunnable();
        //将myRunnable传入Thread;类中
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行了");
    }
}
//输出
 	主线程线程执行了
	Thread-0线程执行了

3.使用Callable和FutureTask创建线程

public class Main03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   		 //创建实现类
        MyCallable myCallable = new MyCallable();
		//创建FutureTask类,该类实现了Runnable接口;
        FutureTask stringFutureTask = new FutureTask(myCallable);
        //将创建的FutureTask的实例传递给Thread类,并启动线程
        new Thread(stringFutureTask).start();

        Object o = stringFutureTask.get();

        System.out.println(o);


    }
}
//MyCallable接口实现Callable接口,其中的call方法相当于我们的run方法
class MyCallable implements Callable{

    @Override
    public Object call() throws Exception {
        int h = 0;
        for(int i = 1; i <100; i++){
            if(i % 2 == 0){
                h+=i;
            }
        }
        return  Thread.currentThread().getName()+"求和为:--"+h;
    }
}

4.使用线程池

public class Main04 {

    public static void main(String[] args) {
        //1.提供指定线程数量的线程池;
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        //2.执行指定的线程操作,需要提供实现Runnable接口和Callable接口的实现类对象;
        executorService.execute(new MyRunnable1());

        //关闭连接池;
        executorService.shutdown();

    }
}
class MyRunnable1 implements Runnable {
    @Override
    public void run() {

        System.out.println("这是使用线程池创建线程");

    }
}
使用线程池的好处:
	1.提高响应速度(减少了线程的创建时间)
	2.降低了资源消耗(重复利用线程池中的线程,不需要每次都创建)
	3.便于管理:	
		corePoolSize:核心池的大小
		maximumPoolSize:最大线程数;
		keepAliveTime:线程没有任务是最多保持多长时间后终止

多线程的常用方法

1.start():启动当前线程;调用当前线程的run();
2.run(): 通常需要重写Thread类中的此方法,将要执行的操作写入该方法中;
3.currentThread(): 静态方法,返回执行当前代码的线程;
4.getName():获取当前线程的名字;
5.setName():设置当前线程的名字;
6.yield():释放当前cpu的执行权;
7.join():在线程A中调用线程B的join(),此时线程A就会进入阻塞状态,直到线程B完全执行完以后,线程A才结束阻塞状态;
8.stop():已过时,当执行此方法是,强制结束当前线程;
9.sleep(long millitime) : 使当前线程睡眠指定的毫秒数,在此期间,该线程处于阻塞状态;
10. isAlive(): 判断当前线程是否存活;

多线程的生命周期

线程生命周期图

线程的安全问题

1.多个线程执行的不确定性造成执行结果的不稳定
2.多个线程对账本的共享,会造成操作的不完整性,会破坏数据;

解决线程的安全问题

解决线程安全的方式有几种?
答:3种;
1.同步代码块—synchronized(同步监视器){需要被同步的代码}

public class SYNdemo01 {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable);
        Thread thread2 = new Thread(myRunnable);

        thread1.start();
        thread2.start();

    }
}
class MyRunnable implements Runnable{
    private int x = 150;
    @Override
    public void run() {
        while (true){
            
            synchronized (this){
                if(x>0){
                    try {
                        Thread.currentThread().sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"窗口卖出了:"+x+"号票");
                    x--;
                }else{
                    break;
                }
            }
        }
    }
}
synchronized(){需要被同步的代码}
	1.操作共享数据的代码,即需要被同步的代码;
	2.共享数据,多个线程同时操作的变量,比如我们现实中的火车票
	3.同步监视器:俗称:,任何一个类的对象,都可以充当锁对象;
		要求:多个线程必须要共用一把锁,即这个锁对象在多线程操作时必须是同一个锁对象;

2.同步方法—被synchronized修饰的方法

public class SYNdemo01 {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable);
        Thread thread2 = new Thread(myRunnable);

        thread1.start();
        thread2.start();

    }
}
class MyRunnable implements Runnable{
    private int x = 150;
    @Override
    public void run() {
        while (true){

            loket();
            if(x<=0){
                break;
            }
            
        }
    }

    //同步方法
    public synchronized void loket(){
        if(x>0){
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"窗口卖出了:"+x+"号票");
            x--;
        }

    }
}

3.Lock锁解决线程安全问题
Lock锁是JDK5.0后加入的,是一个接口,比较常用的是ReentrantLock类,他拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁;

public class LockSuo {

    public static void main(String[] args) {
        Window window = new Window();
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);

        thread1.start();
        thread2.start();
    }
}

class Window implements  Runnable{

    private static int x = 150;
    private ReentrantLock reentrantLock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try{
                reentrantLock.lock();

                if(x>0){

                    try {
                        Thread.currentThread().sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"窗口出售了:"+x+"号票");
                    x--;
                }else{
                    break;
                }
            }finally {
                reentrantLock.unlock();
            }
        }
    }
}

线程安全的单例模式之懒汉式

class BankTest{
    private static BankTest bankTest;

    private BankTest(){

    }
    public static BankTest getBankTest(){
        synchronized (BankTest.class) {
            if (bankTest == null) {

                bankTest = new BankTest();
            }
        }
        return bankTest;
    }
}

线程中的死锁问题

死锁: 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁;
死锁出现后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续;
死锁演示:

public class SYNdemo02 {
    public static void main(String[] args) {

        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();

        new Thread(){
            @Override
            public void run() {
                synchronized (s1){
                    s1.append("a");
                    s2.append("1");
                    try {
                        Thread.currentThread().sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s2){
                        s1.append("b");
                        s2.append("2");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                synchronized (s2){
                    s1.append("c");
                    s2.append("3");
                    try {
                        Thread.currentThread().sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s1){
                        s1.append("d");
                        s2.append("4");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }.start();
    }
}

线程的通信

例题:交替打印1-100;线程1和线程2交替打印;

public class JT {
    public static void main(String[] args) {

        Number number = new Number();
        Thread thread1 = new Thread(number);
        Thread thread2 = new Thread(number);

        thread1.start();
        thread2.start();
    }
}

class Number implements  Runnable {
    private static int x = 1;
    
    @Override
    public void run() {
        while (true) {
           synchronized (this) {
               if (x <= 100) {
                   notify();
                   try {
                       Thread.currentThread().sleep(100);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread().getName() + "打印了:" + x);
                   x++;
                   try {
                       wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               } else {
                   break;
               }
           }

        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值