Java多线程开发基础看这篇就够了

    科技2022-07-15  120

    0.基本概念 0.1进程:是指一个内存中运行的应用程序(现在很多软件是多进程的)。每个进程都有一个独立的内存空间。 0.2线程:是进程中的一个执行路径,共享一个内存空间。线程之间可以自由切换,并发执行。 0.3调度 思考:假设计算机是四核八线程,如何将正在执行的1000+个线程分配出去。 1.分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。 2.抢占式调度 优先让优先级高的线程使用CPU,如果一样高,则随机。JAVA使用的是抢占式调度。 0.4同步与异步 同步:线程排队执行,效率低,但是安全。 异步:线程同时执行,效率高,但是数据不安全。 0.5并发与并行 并发:指两个或多个事件在同一个时间段内发生。 并行:指两个或多个事件在同一时刻发生。 0.6每个线程都拥有自己的栈空间,共用一份堆内存。由一个线程所调用的方法,那么这个方法也会执行在这个线程里面。

    1.两种常见创建线程的方法 1.继承Thread

    package thread; public class MyThread extends Thread { //run方法就是线程要执行的任务方法 @Override public void run() { //这里的代码就是一条新的执行路径 //这个执行路径是触发方式,不是调用run方法,而是通过thread对象的start方法来启动任务 for (int i = 0; i < 10; i++) { System.out.println("锄禾日当午"+i); } } } package thread; public class Demo1 { public static void main(String[] args) { MyThread m = new MyThread(); m.start(); for (int i = 0; i < 10; i++) { System.out.println("汗滴禾下土"+i); } } }

    2.实现Runnable接口

    package thread; public class MyRunnable implements Runnable{ @Override public void run() { //线程的任务 for (int i = 0; i < 10; i++) { System.out.println("锄禾日当午"+i); } } } package thread; public class Demo1 { public static void main(String[] args) { //实现runnable //1 创建一个任务对象 MyRunnable r = new MyRunnable(); //创建一个线程并给他一个任务 Thread t = new Thread(r); //启动线程 t.start(); for (int i = 0; i < 10; i++) { System.out.println("汗滴禾下土"+i); } } }

    3.实现Runnable与继承Thread相比有如下优势 1.通过创建任务,然后给线程分配任务的方式实现多线程,更适合多个线程同时执行任务的情况 2,可以避免单继承所带来的局限性 3,任务与线程是分离的,提高了程序的健壮性 4,后期学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程

    4.实现Runnable的匿名内部类写法

    package thread; public class Demo2 { public static void main(String[] args) { new Thread(){ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("12345"+i); } } }.start(); for (int i = 0; i < 10; i++) { System.out.println("汗滴禾下土"+i); } } }

    5.给线程命名的代码示例

    package thread; public class Demo3 { public static void main(String[] args) { //如何获取线程的名称 System.out.println(Thread.currentThread().getName()); //两种设置线程名称的方式 Thread t = new Thread(new MyRunnable()); t.setName("wwww"); t.start(); new Thread(new MyRunnable(),"锄禾日当午").start(); //不设置的有默认的名字 new Thread(new MyRunnable()).start(); } static class MyRunnable implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } } }

    6.线程休眠sleep

    package thread; public class Demo4 { public static void main(String[] args) throws InterruptedException { //线程的休眠 for (int i = 0; i < 10; i++) { System.out.println(i); Thread.sleep(1000); //1000毫秒 } } }

    7.线程阻塞 不只是线程休眠,理解为所有消耗时间的操作。比如:文件读取,接收用户输入。 8.线程中断 一个线程是一个独立的执行路径,它是否应该结束,应该由其自身决定。给线程T添加中断标记,在sleep和wait等会检查标记。

    package thread; public class Demo5 { public static void main(String[] args) { //线程中断 //y一个线程是一个独立的执行路径,它是否结束应该由其自身决定 Thread t1 = new Thread(new MyRunnable()); t1.start(); for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } //给线程t1添加中断标记 t1.interrupt(); } static class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { //e.printStackTrace(); System.out.println("发现了中断标记,线程自杀"); return; } } } } }

    9.用户线程、守护线程

    package thread; public class Demo6 { public static void main(String[] args) { //线程分为守护线程和用户线程 //用户线程:当一个进程不包含任何的存活的用户线程时,进行结束 //守护线程:守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡。 Thread t1 = new Thread(new MyRunnable()); //设置守护线程 t1.setDaemon(true); t1.start(); for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } static class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }

    10.线程不安全

    package thread; public class Demo7 { public static void main(String[] args) { //线程不安全 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; @Override public void run() { while (count>0){ //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println("卖票结束,余票:"+count); } } } }

    11线程安全1(同步代码块)

    package thread; //线程同步synchronized public class Demo8 { public static void main(String[] args) { Object o = new Object(); //线程不安全 //解决方案1 同步代码块 //格式:synchronized(锁对象){ // // // } 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; private Object o = new Object(); @Override public void run() { //Object o = new Object(); //这里不是同一把锁,所以锁不住 while (true) { synchronized (o) { if (count > 0) { //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count); }else { break; } } } } } }

    12.线程安全2(同步方法)

    package thread; //线程同步synchronized public class Demo9 { public static void main(String[] args) { Object o = new Object(); //线程不安全 //解决方案2 同步方法 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; @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); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count); return true; } return false; } } }

    13线程安全3(显式锁Lock)

    package thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //同步代码块和同步方法都属于隐式锁 //线程同步lock public class Demo10 { public static void main(String[] args) { Object o = new Object(); //线程不安全 //解决方案1 显示锁 Lock 子类 ReentrantLock 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; //参数为true表示公平锁 默认是false 不是公平锁 private Lock l = new ReentrantLock(true); @Override public void run() { while (true) { l.lock(); if (count > 0) { //卖票 System.out.println("正在准备卖票"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count--; System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count); }else { break; } l.unlock(); } } } }

    14线程死锁 注意:在任何有可能导致锁产生的方法里,不要再调用另外一个方法让另外一个锁产生。

    package thread; public class Demo11 { public static void main(String[] args) { //线程死锁 Culprit c = new Culprit(); Police p = new Police(); new MyThread(c,p).start(); c.say(p); } static class MyThread extends Thread{ private Culprit c; private Police p; MyThread(Culprit c,Police p){ this.c = c; this.p = p; } @Override public void run() { p.say(c); } } static class Culprit{ public synchronized void say(Police p){ System.out.println("罪犯:你放了我,我放了人质"); p.fun(); } public synchronized void fun(){ System.out.println("罪犯被放了,罪犯也放了人质"); } } static class Police{ public synchronized void say(Culprit c){ System.out.println("警察:你放了人质,我放了你"); c.fun(); } public synchronized void fun(){ System.out.println("警察救了人质,但是罪犯跑了"); } } }

    15.多线程通信问题

    package thread; public class Demo12 { public static void main(String[] args) { //多线程通信 生产者与消费者问题 Food f = new Food(); new Cook(f).start(); new Waiter(f).start(); } //厨师 static class Cook extends Thread{ private Food f; public Cook(Food f) { this.f = f; } @Override public void run() { for (int i = 0; i < 100; i++) { if(i%2==0){ f.setNameAndTaste("老干妈小米粥","香辣味"); }else { f.setNameAndTaste("煎饼果子","甜辣味"); } } } } //服务员 static class Waiter extends Thread{ private Food f; public Waiter(Food f) { this.f = f; } @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } f.get(); } } } //食物 static class Food{ private String name; private String taste; //true表示可以生产 boolean flag = true; public synchronized void setNameAndTaste(String name,String taste){ if(flag){ this.name = name; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.taste = taste; flag = false; this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void get(){ if(!flag){ System.out.println("服务员端走的菜的名称是:"+name+",味道是:"+taste); flag = true; this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }

    16.用的不多的知识点: 带返回值的线程Callable、四种线程池:缓冲线程池(长度无限制)、定长线程池、单线程线程池、周期性任务定长线程池。

    Processed: 0.015, SQL: 8