多线程详述

多线程中知识点详解


前言

        随着大家的不断学习,恭喜大家进入多线程的学习阶段,在学习之前,可以了解一下本篇文章,可以让同学们学习的更加通透。

一、线程和进程的区别:

​ **进程:**进程是内存中运行的应用程序,每个进程拥有独立的内存空间。

​ **线程:**是进程中的一个执行路径,线程可以并发,一个进程至少有一个线程

​ 线程是在进程基础上的进一步划分,一个进程可有多条线程,

二、创建线程的两种方式:

(1)继承Thread类

public class ThreadTest{
    public static void main(String[] args){
        MyThread t1 = new MyThread();	//创建线程对象
        t1.start();		//线程启动
    }
    static class MyThread extends Thread{		//继承Thread类
        public void run(){		//任务
            System.out.println("Thead1线程执行了")
        }
    }
}

(2)实现Runnable接口

public class RunnableTest{
    public static void main(String[] args){
        Runnable r = new MyRunnable();
        Thread t1 = new Thread(r);
        t1.start();
    }
    static class MyRunnable implements Runnable{
        public void run(){
            System.out.println("Thread线程执行了!");
        }
    }
}

三、Thread中常用的构造器及方法

1、构造器

​ (1)、Thread() 无参构造方法

​ (2)、Thread(Runnable target) 传一个Runnable接口的实现子类

​ (3)、Thread(Runnable target,String name) 传一个Runnable接口的实现子类并设置线程名

​ 2、常用方法

​ (1)、start() void

​ 启动线程。

​ (2)、currentThread static Thread

​ 返回当前正在执行的线程对象的引用 一般使用Thead.currentThread.getName()来获取线程名称。

​ (3)、getId() long

​ 返回当前进程的表示,作用于getName()相同。

​ (4)、getName() String

​ 返回该线程的名称。

​ (5)、getPriority int

​ 返回该线程的优先级。

​ (6)、setPriority(int newPriority) void

​ 设置线程的优先级。

MAX_PRIORITY: 线程可以拥有的最大优先级。 10

MIN_PRIORITY:线程可以拥有的最低优先级。 1

NORM_PRIORITY:分配给线程的默认优先级。 5

​ (7)、interrupt() void

​ 中断此线程,相当于打一个中断标记。

​ (8)、setDaemon(boolean on) void

​ 设置当前线程为守护线程

​ (9)、setName(String name) void

​ 设置该线程的名字。

​ (10)、sleep(long millis) static void

​ 使当前线程休眠

​ (11)、toString String

​ 将当前线程作为字符串输出。

四、线程安全----隐式锁与显式锁

​ 线程安全:所谓线程安全就是所需线程不能并发,需要排队执行。

1、隐式锁:隐式锁分为同步代码块和同步方法两种实现方式,都是运用synchronized关键字,并并且都是创建锁后自动开关锁。

//模拟购票实现:synchronized代码块
public class Demo1{
    public static void main(String[] args){
        Ticket t1 = new Ticket();
        t1.start();
    }
    static class Ticket extends Thread{
        private int count = 10;	//初始票数为10张票
        public void run(){
            while(true){
                synchronized(this){		//synchronized代码块
                    if(count>0){
                        System.out.println("正在出票中····");
                        count--;
                        System.out.println("余票为:"+i);
                    }
                }
            }
        }
    }
}


需要注意的一点:

在使用synchronize(){}代码块时,括号中的内容必须是实现同一个任务的共享的对象。

//模拟购票实现:synchronized 同步方法
public class Demo2 {
    public static void main(String[] args) {
        Object o = new Object();
        // 同步方法
        Runnable run = new Ticket();
        new Thread(run).start();	//启动第一个线程
        new Thread(run).start();	//启动第二个线程
        new Thread(run).start();	//启动第三个线程
    }

    static class Ticket implements Runnable{
        //总票数
        private int count = 10;	//初始票数为10张
        @Override
        public void run() {

            while (true) {
                boolean flag = sale();
                if(!flag){
                    break;
                }
            }
        }
        public synchronized boolean sale(){	//需要排队执行的代码
            if (count > 0) {
                //卖票
                System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);	//休眠1秒,方便看的更细致
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count);
                return true;
            }
                return false;
        }
    }
}

2、显式锁 Lock:隐式锁更倾向于面向对象,是先创建锁对象,然后调用方法,开关锁。

public class Demo3{
    public static void main(String[] args){
        Ticket t1 = new Ticket();
        t1.start();
    }
    static class Ticket extends Thread{
        private Lock lock = new ReentrantLock();
        private int count = 10;
        public void run(){
            while(true){
                lock.lock();	//上锁
                if(count>0){
                    System.out.println("正在出票中····");
                    count--;
                    System.out.println("余票为:"+i);
                }
                lock.unlock();		//解锁
            }
        }
    }
}

五、公平锁与非公平锁

​ 1、定义及优缺点:

非公平锁:公平锁是指多个线程按照申请锁的顺序来获得锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。

​ 优点:等待锁的线程不会饿死。

​ 缺点:效率较低。

非公平锁:非公平锁是多个线程加锁时直接尝试获得锁,获取不到才会进入等待队列的队尾等待。

​ 优点:效率高,线程有几率不阻塞获得锁。

​ 缺点:在队列中的线程有几率会饿死,或者要等待很久才能获得锁。

​ 2、Java中的公平锁与非公平锁

​ (1)隐式锁全部为非公平锁,因为是抢占式调度。

​ (2)在显示锁中,在创建Lock对象时,(Lock lock = new ReentrantLock()),括号中可以传一个布尔类型值,传入true则为公平锁,否

则为非公平锁,默认情况为false。

六、死锁

1、死锁产生的条件:

​ (1)互斥。共享资源同时只能被一个线程访问。

​ (2)占有且等待。线程T1在取得共享资源A的时候,请求等待资源B的时候并不释放资源A。

​ (3)不可抢占。其他线程不能强行抢占线程的资源。

​ (4)循环等待条件。线程T1在持有资源A1,同时在请求等待获取资源B,线程T2在持有资源B,然后在请求等待线程T1的持有资源,

形成了交叉闭环申请。

七、线程池技术

Java通过Executors提供四种线程池,分别为:

newCashedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool: 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor: 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,

LIFO, 优先级)执行。

//缓存线程池:
public class CashedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+
                        "线程启动了!!!");
            }
        });
    }
}
/*执行结果:
		pool-1-thread-1线程启动了!!!
		pool-1-thread-2线程启动了!!!
		pool-1-thread-2线程启动了!!!
*/
//不定长线程池
public class FixedThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });
    }
}
/*执行结果:
		pool-1-thread-1线程启动了!!!
		pool-1-thread-2线程启动了!!!
		pool-1-thread-1线程启动了!!!
*/
//单线程线程池
public class SingleThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newSingleThreadExecutor();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        });
    }
}
/*执行结果:
	pool-1-thread-1线程启动了!!!
	pool-1-thread-1线程启动了!!!
*/
//周期性定长线程池
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolTest {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        /*执行一次
         * 第一个参数:定时执行的任务
         * 第二个参数:第一次执行任务的延迟时间
         * 第三个参数:时间单位
        scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        },2, TimeUnit.SECONDS);*/
        /**
         * 第一个参数:定时执行的任务
         * 第二个参数:第一次执行任务的延迟时间
         * 第三个参数:周期性时间(每隔多长时间执行一次)
         * 第四个参数:时间单位
         */
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了!!!");
            }
        },5,2,TimeUnit.SECONDS);
    }
}

八、lambda表达式

public class LambdaTest {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> System.out.println("线程执行了"),"t1");
        t1.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }
}

总结

            以上就是今天要分享的内容,本篇文章是个人笔记产物,希望大家能够保持对学习的热情,努力学习。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值