学习大纲

  • 线程简介
  • 线程实现(重点)
  • 线程状态
  • 线程同步(重点
  • 线程通信问题
  • 高级主题(线程池)

一、线程简介

1. 多任务

在生活中,我们一般会边吃饭边玩手机,或者边走路边玩手机,这样看起来我们在同时做着多个事情,但是其实我们大脑在同一时间只能处理一件事情,

2.多线程

例子:原来一条路,车太多了,开始堵塞,为了提高效率,我们多增加个车道,从此,妈妈在也不用担心道路阻塞了。玩王者荣耀也是如此,你和队友组队,大家都是多线程执行。

3.进程

在操作系统的运行的程序就是进程。一个进程可以有多个线程。

  • 程序是指令和数据的有序集合,是静态的。
  • 进程是程序的一次执行过程,是动态的,是系统资源分配的单位。
  • 一个进程可以包含多个线程,但至少有一个线程,线程是cpu执行和调度的基本单位。

Java中的多线程是模拟出来的,真的的多线程是指有多个CPU,即 多核,比如 服务器。而模拟出来的cpu,在同一个时间点,cpu只能执行一个代码,因为cpu调度,不同线程切换很快,所以就有同时执行的错觉。

总结来说,就是宏观上并行,微观上串行。

二、线程实现(Thread,Runnable、Callable)

1、三种方式:

  • Thread class ------> 继承 Thread 类 (重点)
  • Runnable 接口 -----> 实现Runnable 接口(重点)
  • Callable 接口 ------> 实现Callable 接口

2.实现代码学习

(1)创建线程方式一:继承Thread 类,重写 run() 方法,调用start()方法开启线程(注意,线程开启不一定执行,由cpu进行调度)

package thread;/*** @Author Janson* @Date 2022/2/24 9:24* @Version 1.0*/
// 注意,线程开启不一定执行,由cpu进行调度
//创建线程方式一:继承Thread 类,重写 run() 方法,调用start()方法开启线程
public class TestThread extends Thread {@Override//重写 run() 方法public void run(){for (int i = 0; i < 200; i++) {System.out.println("我在看代码-----"+i);}}public static void main(String[] args)  {//main 线程,主线程TestThread testThread = new TestThread();//testThread.run();testThread.start();for (int i = 0; i < 20; i++) {System.out.println("我在学习多线程:" + i );System.out.println();}}
}

网图下载例子:

下载图片的类 借助 commons io 包中的 FileUtils 类的 copyURLToFile方法进行 下载 图片

package thread;import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/*** @Author Janson* @Date 2022/2/24 12:32* @Version 1.0*/
public class TestThreadDownlPic extends Thread {private String name;private String url;//构造方法,调用的时候用于传递初始参数public TestThreadDownlPic(String url,String name) {this.name = name;this.url = url;}//重写run方法@Overridepublic void run(){//下载图片的线程的执行体WebDownload webDownload = new WebDownload();webDownload.downloader(url,name);System.out.println("下载了文件名为:" + name);}//主线程 main 方法public static void main(String[] args) {//创建 线程 对象TestThreadDownlPic testThreadDownlPic1 = new TestThreadDownlPic("https://www.todesk.com/image/download/windows_pic.png",//C:\Users\25393\Desktop\img\  该地址为路径,1.jpg为文件名"C:\\Users\\25393\\Desktop\\img\\1.jpg");//如果不写路径,则默认在项目根路径下TestThreadDownlPic testThreadDownlPic2 = new TestThreadDownlPic("https://www.todesk.com/image/logo-text.png","2.jpg");TestThreadDownlPic testThreadDownlPic3 = new TestThreadDownlPic("https://www.todesk.com/image/news/1.jpg","3.jpg");//启动线程testThreadDownlPic1.start();testThreadDownlPic2.start();testThreadDownlPic3.start();}}
//下载图片的类
class WebDownload{public void downloader(String url,String name){try {//借助 commons io 包中的 FileUtils 类的 copyURLToFile方法进行 下载 图片FileUtils.copyURLToFile(new URL(url),new File(name));} catch (IOException e) {e.printStackTrace();System.out.println("执行webdownload类,出现io异常。");}}
}

(2)创建线程方式2 ,实现Runnable接口,重写run() 方法

实现Runnable 接口 实现线程时,需要用Thread 类 的代理进行启动线程,即 将Runnable 接口的实现类的对象,作为Thread 类的参数,创建对象,用该对象启动线程

package thread;import org.apache.commons.io.FileUtils;import java.io.File;
import java.io.IOException;
import java.net.URL;/*** @Author Janson* @Date 2022/2/24 14:48* @Version 1.0*/
public class TestThreadRunnable implements Runnable {private String url;private String name;public TestThreadRunnable(String url,String name){this.name = name;this.url = url;}@Overridepublic void run() {//下载图片的线程的执行体WebDownload webDownload = new WebDownload();webDownload.downloader(url,name);System.out.println("下载了文件名为:" + name);}public static void main(String[] args) {//创建 线程 对象TestThreadRunnable testThreadRunnable1= new TestThreadRunnable("https://www.todesk.com/image/download/windows_pic.png",//C:\Users\25393\Desktop\img\  该地址为路径,1.jpg为文件名"C:\\Users\\25393\\Desktop\\img\\1.jpg");//如果不写路径,则默认在项目根路径下TestThreadRunnable testThreadRunnable2= new TestThreadRunnable("https://www.todesk.com/image/logo-text.png","2.jpg");TestThreadRunnable testThreadRunnable3= new TestThreadRunnable("https://www.todesk.com/image/news/1.jpg","3.jpg");//启动线程, 继承 thread 实现线程时,直接用实现类的对象 调用start方法启动线程//  实现Runnable 接口 实现线程时,需要用Thread 类 的代理进行启动线程,//  即 将Runnable 接口的实现类的对象,作为Thread 类的参数,创建对象,用该对象启动线程new Thread(testThreadRunnable1).start();new Thread(testThreadRunnable2).start();new Thread(testThreadRunnable3).start();}
}
class WebDownload2{public void downloader(String url,String name){try {//借助 commons io 包中的 FileUtils 类的 copyURLToFile方法进行 下载 图片FileUtils.copyURLToFile(new URL(url),new File(name));} catch (IOException e) {e.printStackTrace();System.out.println("执行webdownload类,出现io异常。");}}
}

3、小结

4. 龟兔赛跑

package thread;/*** 龟兔赛跑* @Author Janson* @Date 2022/2/24 15:57* @Version 1.0*/
public class Race implements Runnable {private String winner;@Overridepublic void run() {for (int i=1;i<=100;i++){//让兔子线程 sleepif (Thread.currentThread().getName()=="兔子" && i%10==0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();System.out.println("线程 sleep 异常");}}System.out.println(Thread.currentThread().getName() + "跑了"+ i +"步");//程序终止条件boolean flag = gameOver(i);if (flag){break;}}}//判断是否产生了赢家,产生了,程序终止private boolean gameOver(int steps){//必须要判断winner 是否为空,不判断的话,程序会将另一个线程执行结束才终止if (winner != null){return true;}else if (steps>=100){winner = Thread.currentThread().getName();System.out.println("最后的赢家:"+ winner);return true;}return false;}//main方法  主线程public static void main(String[] args) {Race race = new Race();new Thread(race, "乌龟").start();Thread rabbit = new Thread(race, "兔子");//设置线程的优先级//rabbit.setPriority(Thread.MAX_PRIORITY);rabbit.start();}
}

5、实现Callable 接口

  • 重写call方法
  • 创建线程池对象,用submit 方法启动线程,有返回值
package thread;import java.util.concurrent.*;/*** @Author Janson* @Date 2022/2/24 19:56* @Version 1.0*/
public class TestCallable implements Callable {@Overridepublic Object call() throws Exception {System.out.println("执行多线程了:");return 1;}public static void main(String[] args) throws ExecutionException, InterruptedException {TestCallable testCallable = new TestCallable();ExecutorService executorService = Executors.newCachedThreadPool();Future submit = executorService.submit(testCallable);System.out.println(submit.get());executorService.shutdownNow();}
}

6.静态代理模式

  • 真实对象和代理对象都要实现同一个接口
  • 代理对象要代理真实对象,即 在代理对象中调用真实对象
package thread;/*** @Author Janson* @Date 2022/2/24 21:16* @Version 1.0*/
// 静态代理模式总结://真实对象和代理对象都要实现同一个接口//代理对象要代理真实对象,即 在代理对象中调用真实对象
public class StaticProxy {public static void main(String[] args) {//You you = new You();//WeddingCompany weddingCompany = new WeddingCompany(you);//weddingCompany.happyMarry();//下边一行 ,和上边三行功能一样new WeddingCompany(new You()).happyMarry();//new WeddingCompany(()-> System.out.println("我爱你")).happyMarry();}
}
// 结婚接口
interface Marry{void happyMarry();
}
//结婚对象  You
class You implements Marry{@Overridepublic void happyMarry() {System.out.println("janson要娶媳妇了。");}
}
//代理公司,代理你办理一切事宜
class WeddingCompany implements Marry{private Marry target;public WeddingCompany(Marry marry) {this.target = marry;}@Overridepublic void happyMarry() {before();target.happyMarry(); //执行真实的对象after();}private void after() {System.out.println("结婚后,睡媳妇");}private void before() {System.out.println("结婚前,接媳妇");}
}

7、Lambda表达式

(1)简介

  • 函数式接口:
    *任何接口,如果只包含一个抽象方法,那么它就是一个函数式接口。
    *对于函数式接口,我们可以通过 lambda 表达式来创建该接口的对象,简化编程

  • 匿名内部类与lambda表达式存在相似之处:
    * = 前边直接用 接口 创建对象,在 = 后边,不一样,
    *匿名内部类时 new 接口{ 重写接口中的方法};
    *lambda 表达式 是 ()->{需要执行的语句};
    *注意:两个类的 } 后边都由 ; ,不要忘记。

(2)代码示例

package thread;
//为什么要使用 lambda 表达式//避免匿名内部类定义过多//可以让代码看起来更简洁//去掉了一堆没有意义的代码,只留下核心的代码
/*** @Author Janson* @Date 2022/2/25 10:26* @Version 1.0*/
/***函数式接口:*任何接口,如果只包含一个抽象方法,那么它就是一个函数式接口。*对于函数式接口,我们可以通过 lambda 表达式来创建该接口的对象,简化编程*/
public class TestLambda {public static void main(String[] args) {//外部类实现接口Like1 like1 = new Like1();like1.lambda();//内部类实现接口Like2 like2 = new Like2();like2.lambda();//3.局部内部类class Like3 implements ILike{@Overridepublic void lambda() {System.out.println("I like lambda3");}}Like3 like3 = new Like3();like3.lambda();/*** 匿名内部类与lambda表达式存在相似之处:* = 前边直接用 接口 创建对象,在 = 后边,不一样,*匿名内部类时 new 接口{ 重写接口中的方法};*lambda 表达式 是 ()->{需要执行的语句};*注意:两个类的 } 后边都由 ; ,不要忘记。*///4.匿名内部类,没有类名称,用接口进行创建ILike like4 =   new ILike() {@Overridepublic void lambda() {System.out.println("I like lambda4");}};like4.lambda();//5.用lambda 表达式ILike like5 = () -> {System.out.println("I like lambda5");};like5.lambda();}//2.内部类static class Like2 implements ILike{@Overridepublic void lambda() {System.out.println("I like lambda2");}}
}//定义一个函数式接口
interface ILike{void lambda();
}
//1.实现类  外部类
class Like1 implements ILike{@Overridepublic void lambda() {System.out.println("I like Lambda1");}
}

三、线程状态(五个状态)

  • 创建

  • 就绪

  • 运行

  • 阻塞

  • 死亡
    (1)状态讲解


    (2)线程方法

    (3)线程停止

  • 1.建议线程正常停止 ——————> 利用次数,不建议死循环

  • 2.建议使用标志位------> 设置一个标志位

  • 3.不要使用stop 或者 destory 等过时 或者不建议使用的方法


代码实现:

package thread;/*** @Author Janson* @Date 2022/2/25 12:26* @Version 1.0*/
//测试 stop
//    1.建议线程正常停止 ——————> 利用次数,不建议死循环
//    2.建议使用标志位------> 设置一个标志位
//    3.不要使用stop 或者 destory 等过时 或者不建议使用的方法
public class ThreadStop  implements Runnable{private  boolean flag = true;public static void main(String[] args) {ThreadStop threadStop = new ThreadStop();new Thread(threadStop).start();for (int i = 0; i <1000 ; i++) {System.out.println("main线程" + i);if (i==900){threadStop.stop();System.out.println("线程该停止了");}}}//写一个公开的方法停止线程public  void stop() {this.flag = false;}@Overridepublic void run() {int i = 0;while (flag){System.out.println("run ...... Thread..." + i++);}}
}

(4)线程 休眠 sleep

  • 作用:模拟网络延时, 放大问题的发生性
  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep存在异常InterruptedException;
  • sleep时间达到后线程进行就绪状态
  • sleep可以模拟网络延时,倒计时等;
  • 每一个对象都有一个锁,sleep不会释放锁;

代码:倒计时例子

package thread;import java.text.SimpleDateFormat;
import java.util.Date;/*** @Author Janson* @Date 2022/2/25 15:23* @Version 1.0*/
//模拟网络延时, 放大问题的发生性
public class TestThreadSleep implements Runnable{@Overridepublic void run() {while (true){int i = 10;for (; i >0; i--) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i);}if (i == 0)break;;}}public static void main(String[] args) throws InterruptedException {//TestThreadSleep testThreadSleep = new TestThreadSleep();//new Thread(testThreadSleep).start();Date date = new Date(System.currentTimeMillis());while (true){//ms 级别Thread.sleep(1000);int i = 0;System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));i++;date = new Date(System.currentTimeMillis());if (i == 10)break;}}
}

(5)线程礼让 yield

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞;
  • 将线程从运行状态转为就绪状态;
  • 让cpu重写调度,礼让不一定成功,看cpu心情。

代码

package thread;/*** @Author Janson* @Date 2022/2/27 12:49* @Version 1.0*/
public class TestThreadYield implements Runnable{@Overridepublic void run() {System.out.println("副线程执行前----");System.out.println("副线程执行后----");}public static void main(String[] args) {TestThreadYield testThreadYield = new TestThreadYield();new Thread(testThreadYield).start();System.out.println("main 线程执行前----");//主线程先执行,遇到该命令,主线程就会转为 就绪 状态,与 副线程 重写开始竞争cpu//谁竞争到,谁就先执行Thread.yield();System.out.println("main 线程执行后----");}
}

(6)线程强制执行 join

  • Join 合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞
  • 类似于插队
  • 抢占方式,一旦该线程启动,就会抢占cpu,直到该线程执行结束

代码实现:

package thread;/***  join() 抢占方式,一旦该线程启动,就会抢占cpu,直到该线程执行结束* @Author Janson* @Date 2022/2/27 12:42* @Version 1.0*/
public class TestThreadJoin implements Runnable {@Overridepublic void run() {for (int i = 0; i <200 ; i++) {System.out.println("测试线程执行------");}}public static void main(String[] args) throws InterruptedException {TestThreadJoin testThreadJoin = new TestThreadJoin();new Thread(testThreadJoin).start();//抢占cpu,接下来 cpu 只执行该线程,而不执行主线程,直至该线程执行结束new Thread(testThreadJoin).join();for (int i = 0; i <1000 ; i++) {System.out.println("main线程执行------");}}
}

(6)线程状态(Thread.State())

(7)线程优先级

  • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度按个线程来执行。
  • 线程优先级用数字表示,范围1-10;
  • Thread.MIN_PRIORITY = 1;
  • Thread.MAX_PRIORITY = 10;
  • Thread.NORM_PRIORITY = 5;
  • 使用以下方法改变或获取优先级,优先级 设置要 先于线程启动
  • getPriority() , setPriority(int xxx),

代码实现:

package thread;/*** 优先级设置* @Author Janson* @Date 2022/2/27 12:56* @Version 1.0*/
public class TestThreadPriority implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+"线程的优先级为:"+Thread.currentThread().getPriority()+"执行次数" + i);}}public static void main(String[] args) {TestThreadPriority testThreadPriority = new TestThreadPriority();//线程1Thread thread1 = new Thread(testThreadPriority,"1线程");thread1.setPriority(Thread.MAX_PRIORITY);thread1.start();//线程2Thread thread2 = new Thread(testThreadPriority,"2线程");thread2.setPriority(8);thread2.start();//线程3Thread thread3 = new Thread(testThreadPriority,"3线程");thread3.setPriority(4);thread3.start();//线程4Thread thread4 = new Thread(testThreadPriority,"4线程");thread4.setPriority(1);thread4.start();//线程5Thread thread5 = new Thread(testThreadPriority,"5线程");thread5.setPriority(6);thread5.start();System.out.println("main线程的优先级为:" + Thread.currentThread().getPriority());}
}

(8)守护线程 Daemon

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如,后台记录操作日志,监控内存,垃圾回收等待。
  • 守护线程会一直执行到所有线程终止,守护线程才会慢慢停止

代码实现:

package thread;/*** 守护进程* 线程分为 用户线程 和 守护线程,setDaemon() 中的参数默认为false,既默认线程为用户线程* 守护线程会一直执行到所有线程终止,守护线程才会慢慢停止* 用户线程就是执行自己的生命周期* @Author Janson* @Date 2022/2/27 14:50* @Version 1.0*/
public class TestThreadDaemon  {public static void main(String[] args) {God god = new God();Person person = new Person();Thread thread = new Thread(god);//This method must be invoked before the thread is started.thread.setDaemon(true);thread.start();new Thread(person).start();}
}
class God implements Runnable{@Overridepublic void run() {while (true){System.out.println("上帝守护者你");}}
}
class Person implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("人的一生要活得快快乐乐------" + i);}System.out.println("-----------good bye-----------world");}}

四、线程同步(synchronized,ReentrantLock,两种锁机制)

(1)锁机制

多个线程操作同一个资源时,造成线程不安全问题,例如上万人抢一百张票,就会出现数据紊乱问题,就需要线程同步解决问题。

  • 采用线程锁,synchronized ,既可以锁方法,又可以 锁代码块
  • ReentrantLock 只能锁代码块
synchronized (obj){//需要锁的执行体}

代码实现:买票案例

package thread.sysChronize;/*** 线程同步* @Author Janson* @Date 2022/2/27 15:45* @Version 1.0*/
public class TestThreadSysChronized {public static void main(String[] args) {BuyTicket buyTicket = new BuyTicket();new Thread(buyTicket,"小黑").start();new Thread(buyTicket,"小白").start();new Thread(buyTicket,"小黄牛").start();//String name = buyTicket.getClass().getName();//System.out.println(name);//String simpleName = buyTicket.getClass().getSimpleName();//System.out.println(simpleName);}
}
class BuyTicket implements Runnable{private int ticket = 10;//线程停止标志位private boolean flag  = true;@Overridepublic void run() {while (flag){buy();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}//采用线程锁,synchronized ,既可以锁方法,又可以 锁代码块public  synchronized void buy(){//判断是否有票if (ticket<=0){flag = false;return;}System.out.println(Thread.currentThread().getName() + "买到了第 " + ticket-- + " 票");}
}

代码实现二——银行转账案例

package thread.sysChronize;import java.util.Arrays;/*** 银行账户转账案例,学习 线程不安全情况下, 加锁解决线程不安全问题* @Author Janson* @Date 2022/2/28 18:54* @Version 1.0*/
public class TestSyncBank{private static final int ACCOUNTS = 100;private static final int INITIALBALANCE = 1000;private static final int MAXAMMOUNT = 1000;public static void main(String[] args) {Bank bank = new Bank(ACCOUNTS,INITIALBALANCE);//可重入锁,在run方法中加,或者 在 lambda 表达式中加上,//ReentrantLock reentrantLock = new ReentrantLock();for (int i = 0; i < ACCOUNTS; i++) {int fromaccount = i;//调用线程接口,采用lambda 表达式进行,也可以实现通过该接口,重写run方法Runnable runnable = ()->{//reentrantLock.lock();int  toaccount = (int) (ACCOUNTS * Math.random());int amount = (int) (MAXAMMOUNT * Math.random());//调用转账方法bank.transfer(amount,fromaccount,toaccount);try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}finally {//reentrantLock.unlock();}};new Thread(runnable).start();}}
}class Bank{private int[] account;private int initBalance;public Bank(int account,int initBalance) {this.account = new int[account];this.initBalance = initBalance;Arrays.fill(this.account,this.initBalance);}//转账方法//给 transfer 加锁synchronized,不然会出现线程不安全 ,加锁在方法上public synchronized void transfer(int amount,int fromaccount,int toaccount){System.out.println(Thread.currentThread());if (account[fromaccount] >= amount){account[fromaccount] -= amount;}elsereturn;System.out.printf("%d from %d to %d\n",amount,fromaccount,toaccount);account[toaccount] += amount;System.out.println("各个账户的总余额:" + getTotalBalance());}//获取所有账户的余额,正常来说 是 100000private int getTotalBalance() {int sum = 0;for (int i = 0; i < account.length; i++) {sum += account[i];}return sum;}
}

(2)死锁

  • 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步代码块同时拥有“两个以上对象的锁”时,就可能发生死锁。

五、线程通信问题

六、线程池

Java多线程,原来如此简单?相关推荐

  1. Java多线程实现简单动画(小球运动)效果

    目录 目录 1.多线程的两种实现方式 1.0.关于多线程理解 1.1.Runnable 1.2.Thread 2.实现动画效果的两种方式 2.0.实现过程理解 2.1.画板(JPanel)线程 2.2 ...

  2. Java多线程实现简单抢红包

    抢红包是在并发场景下操纵和获取资源,只需要将操作和获取的过程建立线程安全机制即可: 抢红包需要多线程同时访问同一共享资源,所以将共享资源作为成员变量注入线程类中供其调用 (使用操纵内存的方式): 实现 ...

  3. java点名代码滚动_JAVA多线程实现简单的点名系统

    效果图如下: CMain函数: package com.shubing.main; public class CMain { public static void main(String[] args ...

  4. Java多线程中使用ReentrantLock、synchronized加锁 简单举例

    Java多线程中使用ReentrantLock.synchronized加锁 简单举例 public class Demo {final static Lock lock = new Reentran ...

  5. java多线程教程_java 基础教程之多线程详解及简单实例

    java 多线程详解 在这篇文章里,我们关注多线程.多线程是一个复杂的话题,包含了很多内容,这篇文章主要关注线程的基本属性.如何创建线程.线程的状态切换以及线程通信. 线程是操作系统运行的基本单位,它 ...

  6. java 线程死锁简单例子_java 多线程死锁详解及简单实例

    java 多线程死锁 相信有过多线程编程经验的朋友,都吃过死锁的苦.除非你不使用多线程,否则死锁的可能性会一直存在.为什么会出现死锁呢?我想原因主要有下面几个方面: (1)个人使用锁的经验差异 (2) ...

  7. 40个Java多线程问题总结

    (转) 这篇文章作者写的真是不错 40个问题汇总 1.多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所 ...

  8. Java多线程学习处理高并发问题

    在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...

  9. Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)

    Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...

  10. Java多线程发展简史

    摘自: http://www.raychase.net/698 这篇文章,大部分内容,是周五我做的一个关于如何进行Java多线程编程的Knowledge Sharing的一个整理,我希望能对Java从 ...

最新文章

  1. ML基石_3_TypesOfLearning
  2. 直播报名 | NVIDIA公开课:Style-Gan的架构与实现
  3. 微信小程序码buffer转为图片php,微信小程序将网络图片转成base64数据
  4. android开发相关资料整理【2011-11-10】
  5. C# 爬虫:疫情实时信息图
  6. css 计算属性的应用_如何使用一点CSS Grid魔术设计计算器应用
  7. 【基础神经网络汇总】
  8. 手动配置 hibernate 项目
  9. WINDOWS下获得DLL所在目录的代码
  10. paip.输入法编程--词频调整原则--发音长度优先
  11. Linux-Input入门-一次愉快的源码分析
  12. 服务器将系统盘,如何将Windows服务器系统的inetpub目录移到其它盘
  13. 他把菜品变成远销省外的零食,经过口口相传,月卖70万
  14. 飞机飞行轨迹可视化Tacview
  15. 吃透Chisel语言.33.Chisel进阶之硬件生成器(二)——Chisel组合逻辑电路生成:以BCD编码表为例
  16. Python数据挖掘-NLTK文本分析+jieba中文文本挖掘
  17. 【C++代码】区间重叠问题
  18. 渗透测试安全检测漏洞
  19. 【CSDN 2021 年度总结】半年涨粉11万,铁杵磨成针
  20. 哈尔滨理工大学第七届程序设计竞赛初赛 题集

热门文章

  1. nginx——不同前端项目共用一个端口
  2. Seay代码审计工具
  3. javafx 带图片的按钮菜单_wordpress如何制作超级菜单(mega menu)
  4. ${VAR}部分说明及用法
  5. (六)可压缩气体的一元流动
  6. 计算机科学博士上海纽约大学,徐立华 - 上海纽约大学 - 计算机科学
  7. MATLAB代码:全面ADMM算法代码,实现了三种ADMM迭代方式
  8. 你知道什么是纳米团簇吗
  9. 51单片机学习:LCD1602液晶显示实验
  10. C语言俄罗斯方块统计消行,求助 关于俄罗斯方块如何消行(附上消行部分代码)...