java多线程及线程同步机制

204 阅读3分钟

线程和多线程的概念及拓展

线程:线程是进程的细化,是程序内部的一条执行路径。

多线程:一个进程在同一时间内进行多个线程,操作系统能同时运行多个任务。

cpu调度:分时调度:所有线程轮流使用cpu的使用权,并且平均分配每个线程占用cpu的时间。 抢占式调度:让优先级高的线程以较大概率获得cpu的使用权,如果优先级相同,那么会随机选择一个线程获得cpu的使用权。【java使用的就是抢占式调度】【线程是cpu调度的最小单位】

线程的创建方式

一,继承java.lang.Thread类

js 代码如下

public class ThreadTest01 extends Thread{

    public ThreadTest01(String name) {
        super(name);
    }
    public void run(){

    }

js 主线程

public class Test {
    public static void main(String[] args) {
        ThreadTest01 t1 = new ThreadTest01("测试线程1");
        ThreadTest01 t2 = new ThreadTest01("测试线程2");
        ThreadTest01 t3 = new ThreadTest01("测试线程3");
        t1.start();
        t2.start();
        t3.start();
    }
  }
}

注意: 1,start()方法调用后不会立刻启动多线程代码,而是使得线变成可运行的状态,什么时候运行取决于操作 系统。线程的执行不是有序的而是乱序的,随机的;

2,start()方法不可以重复调用,人如果重复调用会出现illegalThreadStateExcption

3.程序启动运行main的时候。jvm会启动一个进程,主线程mian在main()调用时被创建,随着satrt() 方法调用,其他线程也启动了。

二,实现java.lang.Runable接口

js 代码如下

public class ThreadTest02 implements Runnable{

    private String name;
    public ThreadTest02(String name){
    this.name=name;
    }
    @Override
    public void run() {
        
    }

注意:

1,ThreadTest02类通过实现Runnable接口的方式使得自己拥有多线程的特征,但实际上Thread类也实 现了Runnable接口

Thread和Runnable的区别

由于Java面向对象的继承性是单继承性,因此使用继承于Thread类的方式实现多线程不利于解决资源共享的问题,而且通过实现Runnable接口的方式实现多线程在处理资源共享等问题方面相对有利。

利用线程同步机制来解决线程安全的问题

方式一,同步代码块
public class ThreadTest01 extends Thread{
    private static int ticket=100;

    public ThreadTest01(String name) {
        super(name);
    }
    public void run() {

        while (true) {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized (ThreadTest01.class) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

说明:这里使用了关键字synchronized,通过利用同步监视器来确保线程安全,但这样做也有弊端【cpu资源的浪费,效率低下】

方式二,同步方法
public class ThreadTest02 implements Runnable{
    private static int ticket=100;
    private String name;
    public ThreadTest02(String name){
        this.name=name;
    }
    @Override
    public synchronized void run() {

        while (true) {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
                if(ticket>0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                }else{
                    break;
            }
        }
    }
}

说明:这里则是使用synchronized关键字来修饰run方法来解决线程安全问题

对两种方法的说明

工作机制: 当多个线程中的一个线程进入run方法体中视时,其他的线程只能在同步监视器同步的代码之外等候,直到进入的线程执行完毕,下一个线程才能够进入;

两种方法均有弊端,都浪费了cpu资源

拓展方法:使用ReentrantLock类的对象调用lock(),unlock()方法

public class ThreadTest03 implements Runnable{
    private int ticket=100;
    ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        while (ticket!=0) {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            reentrantLock.lock();
                if(ticket>0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                }else{
                    break;
            }
            reentrantLock.unlock();
        }
    }
}