1.JVM运行程序原理

  • 由Java命令会启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法。所以main方法运行在主线程中。在此之前的所有程序都是单线程的。
  • JVM的启动是单线程还是多线程的?
    • 多线程:最低启动了两个线程,用户线程 + 垃圾回收线程(先启动)
    • 垃圾回收线程:先启动,斗则很容易内存溢出。

2.如何实现多线程的程序

  • 线程是依赖进程存在的,应该先创建一个进程出来。
  • 进程是由系统创建的,所以应该去调用系统功能创建一个进程。
  • Java不能直接调用系统功能,所以没有办法直接实现多线程程序。
  • 但是,可以调用C/C++写好的程序来实现多线程程序。由C/C++去调用系统功能创建进程,然后提供一些类供Java去调用。

3.创建多线程的方式(3种)

(1)继承Thread

  • 步骤

    • (1)自定义类MyThread继承Thread类
    • (2)重写run()方法
      • 为什么要重写run()方法?

        • 不是类中多有代码都需要被线程执行。所以将需要被线程执行的代码放在run()中。
      • 调用run()为什么是单线程的?
        • 因为run()直接调用就相当于普通的方法调用,所以看到的是单线程的效果。
      • 如何获取线程对象的名称? getName()
        • 线程名称为什么是Thread-X编号?

          • Thread类构造器中有init()方法,方法中传入参数:同步方法nextThreadNum()。

            • 同步方法nextThreadNum():return threadInitNumber++;int类型,初始化从0开始。
        • 如何设置线程对象的名称呢?
          • t.setName("名称");
        • 如何获取main()方法所在线程对象的名称?
          • System.out.println("Thread.currentThread().getName()");
    • (3)启动线程
// MyThread.java
public class MyThread extends Thread {@Overridepublic void run() {// 一般来说,被线程执行的代码都是很好使的。用循环模拟for(int i = 0; i < 100; ++i){System.out.println(getName() + "------" + i);}}
}// MyThreadTest.java
public class MyThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("线程1");t2.setName("线程2");t1.start();t2.start();}
}

(2)实现Runnable接口

  • 步骤

    • (1)自定义类MyRunnable实现Runnable接口
    • (2)重写run()
    • (3)创建MyRunnable类的对象
    • (4)创建Thread类的对象,把(3)步骤的对象作为构造参数传递
  • 实现接口方式的优点
    • 可以避免由于Java单继承带来的局限性
    • 适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码、数据有效分离,较好的体现了面向对象的设计思想
// MyRunnable.java
public class MyRunnable implements Runnable{@Overridepublic void run() {for(int i = 0; i < 10; ++i){// 实现接口的方式不能直接使用Thread类的方法,但是可以间接使用System.out.println(Thread.currentThread().getName() + "------" + i);}}
}// MyRunnableTest.java
public class MyRunnableTest {public static void main(String[] args) {MyRunnable r = new MyRunnable();// 方式1
//        Thread t1 = new Thread(r);
//        Thread t2 = new Thread(r);
//        t1.setName("线程1");
//        t2.setName("线程2");// 方式2Thread t1 = new Thread(r,"线程1");Thread t2 = new Thread(r,"线程2");t1.start();t2.start();}
}

(3)实现Callable接口(带泛型)

  • 这里的泛型指的是call()的返回值类型。
  • 如果需要调用线程后返回结果:用Callable方式
  • 依赖于线程池而存在,故掌握前两种最重要。
/*** 线程求和案例*/
public class MyCallable implements Callable<Integer> {private int number;public MyCallable(int number){this.number = number;}@Overridepublic Integer call() throws Exception {int sum = 0;for(int i = 1; i <= number; ++i){sum += i;}return sum;}
}public class MyCallableDemo {public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService pool = Executors.newFixedThreadPool(2);Future<Integer> f1 = pool.submit(new MyCallable(100));Future<Integer> f2 = pool.submit(new MyCallable(200));Integer i1 = f1.get();Integer i2 = f2.get();System.out.println(i1);System.out.println(i2);pool.shutdown();}
}

4.线程调度的两种模型

  • 线程调度的两种模型

    • 分时调度模型:公平,无饥饿

      • 所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
    • 抢占式调度模式(Java使用)
      • 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个。优先级高的线程获取CPU时间片相对多一些。
  • 如何设置和获取线程优先级?
    • 线程默认优先级:5.
    • 线程优先级范围:1~10
    • java.lang.IllegalArgumentException非法参数异常:当设置优先级输入参数不在1~10范围内时,抛出此异常。
    • 线程优先级别高仅仅表示线程获取CPU时间片的几率高,但是要在次数比较多时,或者多次运行时才能看到比较好的效果。
// ThreadPriority.java
public class ThreadPriority extends Thread{@Overridepublic void run() {for(int i = 0; i < 100; ++i){System.out.println(getName() + "------" + i);}}
}// ThreadPriorityTest.java
public class ThreadPriorityTest {public static void main(String[] args) {ThreadPriority t1 = new ThreadPriority();ThreadPriority t2 = new ThreadPriority();t1.setName("线程1");t2.setName("线程2");t1.setPriority(10);t2.setPriority(2);t1.start();t2.start();}
}

5.线程控制

  • 线程休眠:静态方法 public static void sleep()
// MyThread.java
public class MyThread extends Thread {@Overridepublic void run() {for(int i = 0; i < 100; ++i){System.out.println(getName() + "------" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}// MyThreadTest.java
public class MyThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("线程1");t2.setName("线程2");t3.setName("线程3");t1.start();t2.start();t3.start();}
}
  • 等该线程执行完了,再执行其他的线程:final方法 public final void join()
// MyThreadTest.java
public class MyThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("线程1");t2.setName("线程2");t3.setName("线程3");t1.start();try {// 等线程1全部执行完了,再执行其他的线程。t1.join();} catch (InterruptedException e) {e.printStackTrace();}t2.start();t3.start();}
}
// 运行结果
线程1------0
线程1------1
线程1------2
线程1------3
线程1------4
线程1------5
线程1------6
线程1------7
线程1------8
线程1------9
线程2------0
线程3------0
线程2------1
线程2------2
线程2------3
线程2------4
线程2------5
线程2------6
线程3------1
线程3------2
线程3------3
线程3------4
线程3------5
线程2------7
线程3------6
线程2------8
线程3------7
线程2------9
线程3------8
线程3------9
  • 礼让线程

    • public static void yield()
    • 暂停当前正在执行的线程对象,并执行其他的线程。
    • 让多个线程的执行更加和谐了,但是不能靠他保证一人一次。
// MyThread.java
public class MyThread extends Thread {@Overridepublic void run() {for(int i = 0; i < 10; ++i){System.out.println(getName() + "------" + i);Thread.yield();}}
}
  • 守护线程

    • public final void setDaemon()
    • 将该线程标记为守护线程或用户线程
    • 当正在运行的线程都是守护线程时,JVM退出。
    • 该方法必须在被守护线程前调用。
    • 被守护线程死时,守护线程获取到CPU的时间片,会执行完再死掉。
// MyThreadTest.java
public class MyThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("关羽");t2.setName("张飞");// 设置守护线程t1.setDaemon(true);t2.setDaemon(true);t1.start();t2.start();Thread.currentThread().setName("刘备");for(int i = 0; i < 5; ++i){System.out.println(Thread.currentThread().getName() + "------" + i);}}
}// 运行结果
关羽------0
刘备------0
张飞------0
刘备------1
关羽------1
刘备------2
张飞------1
刘备------3
关羽------2
刘备------4
张飞------2
关羽------3
张飞------3
关羽------4
张飞------4
关羽------5
张飞------5
关羽------6
张飞------6
关羽------7
张飞------7
关羽------8
关羽------9
  • 停止线程

    • public final void stop()
    • 让线程停止,后面的代码都不执行。
    • 该方法已经横线划掉了,但是还可以用。
    • 不建议使用,太暴力了。
// MyThread.java
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("开始执行:" + new Date());try {Thread.sleep(10000);} catch (InterruptedException e) {System.out.println("线程被终止了!");}System.out.println("结束执行:" + new Date());}
}// MyThreadTest.java
public class MyThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();// 超过3s,就中断线程try {Thread.sleep(3000);t1.stop();} catch (InterruptedException e) {e.printStackTrace();}}
}// 运行结果
开始执行:Wed Apr 28 15:06:51 CST 2021
  • 中断线程

    • public void interrupt()
    • 把线程的状态终止,并抛出一个InterruptedException异常。
// MyThreadTest.java
public class MyThreadTest {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();// 超过3s,就中断线程try {Thread.sleep(3000);t1.interrupt();} catch (InterruptedException e) {e.printStackTrace();}}
}// 运行结果
开始执行:Wed Apr 28 15:07:46 CST 2021
线程被终止了!
结束执行:Wed Apr 28 15:07:49 CST 2021

6.线程生命周期图5个   线程状态转换图7个

  • 新建:创建线程对象
  • 就绪:有执行资格,没有执行权
  • 运行:有执行资格,有执行权
  • 阻塞:没有执行资格,没有执行权。(同步阻塞/等待阻塞/其他阻塞)由于一些操作让线程处于了该状态。另外一些操作可以把它激活,激活后处于就绪状态。
  • 死亡:线程对象变成垃圾,等待被回收

7.多线程练习

卖电影票

  • 某电影院正在上映一部电影,共有100张票,有3个售票窗口,请设计一个程序模拟该电影院售票。
  • 继承Thread类方式:不合理
  • 使用Runnable接口的方式:更好的将数据与代码分离

线程安全问题

  • 出现线程安全的原因

    • 是否是多线程环境
    • 是否有共享数据
    • 是否有多条语句操作共享数据
  • 解决思想:
    • 针对第三条,前两条不能处理
    • 把多条语句操作共享数据的代码给包成一个整体,让某个线程执行时,别的线程不能执行——同步机制
  • 同步机制
    • 特点:多个线程使用的是同一个锁对象。
    • 优点:解决了多线程的安全问题。
    • 缺点:当线程特别多时,每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

同步机制实现1

  • 同步的两种方式

    • 同步代码块
    • 同步方法
  • synchronized(对象){需要同步的代码;}
    • 对象:锁,多个线程必须是同一把锁
    • 同步代码块的锁对象可以是任意的
    • 需要同步的代码:多条语句操作共享数据的代码
// SellTicket.java
public class SellTicket implements Runnable {// 共享资源private int tickets = 100;// 锁对象可以是任意的private Object obj = new Object();// private Test obj = new Test();@Overridepublic void run() {// 为了模拟一直有票while(true){if(tickets > 0){synchronized (obj){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");}}}}class Test{}
}// SellTicketDemo.java
public class SellTicketDemo {public static void main(String[] args) {// 创建一个资源:一个数据SellTicket st = new SellTicket();// 创建三个线程Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");// 启动线程t1.start();t2.start();t3.start();}
}
    • 同步方法:把synchronized加在方法上

      • 同步方法的锁对象:this
      • // SellTicket.java
        public class SellTicket implements Runnable {// 共享资源private int tickets = 100;@Overridepublic synchronized void run() {// 为了模拟一直有票while(true){if(tickets > 0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");}}}
        }
        
    • 静态方法的锁对象:类的字节码文件对象。
      • synchronized SellTicket.class
  • 线程安全的类
    • StringBuffer
    • Hashtable
    • Vector
      • 即是线程安全,也不用它,效率太低
      • 一般用
List<String> list = Collections.synchronizedList(new ArrayList<String>());

同步机制实现2

  • Lock是一个接口
  • 可以明确的看到什么时候加锁,什么时候放锁
    • void lock()
    • void unlock()
  • 实现类:ReentrantLock
// SellTicket.java
public class SellTicket implements Runnable {// 共享资源private int tickets = 100;// 创建锁对象private Lock lock = new ReentrantLock();@Overridepublic void run() {// 为了模拟一直有票while(true){try {// 加锁lock.lock();if(tickets > 0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");}} finally {// 如果发生异常可以不用catch,但是一定要把锁释放掉lock.unlock();}}}
}// SellTicketDemo.java
public class SellTicketDemo {public static void main(String[] args) {// 创建一个资源:一个数据SellTicket st = new SellTicket();// 创建三个线程Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");// 启动线程t1.start();t2.start();t3.start();}
}
  • 同步的弊端

    • 效率低
    • 容易产生死锁
      • 两个或者两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
      • 面试题:写一个死锁Demo(圆桌上人吃饭餐具互相持有一个且等待的问题)
      • public class MyLock {// 创建两个锁对象,模拟一副筷子的两只public static final Object objA = new Object();public static final Object objB = new Object();
        }public class DieLock extends Thread{private boolean flag;public DieLock(boolean flag){this.flag = flag;}@Overridepublic void run() {if(flag){synchronized (MyLock.objA){System.out.println("if objA");synchronized (MyLock.objB){System.out.println("if objB");}}} else {synchronized (MyLock.objB){System.out.println("else objB");synchronized (MyLock.objA){System.out.println("else objA");}}}}
        }public class DieLockDemo {public static void main(String[] args) {DieLock dl1 = new DieLock(true);DieLock dl2 = new DieLock(false);dl1.start();dl2.start();}
        }

生产者消费者模型

  • 线程间通信问题:不同种类的线程(生产者线程、消费者线程)间针对同一个资源的操作。

    • 生产和消费的应该是用一个资源——线程通信

      • 实现:在外界把这个数据生产出来,通过构造方法传递给生产线程和消费线程。
      • 线程安全问题:生产者和消费者加的锁必须是同一把。

public class Student {String name;int age;
}public class SetThread implements Runnable{private Student s;private int x = 0;public SetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized (s){if (x % 2 == 0){s.name = "林青霞";s.age = 27;} else {s.name = "刘意";s.age = 30;}x++;}}}
}public class GetThread implements Runnable{private Student s;public GetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized (s){System.out.println(s.name + "------" + s.age);}}}
}/*** 分析:*      资源类:Student*      设置学生数据:SetThread(生产者)*      获取学生数据:GetThread(消费者)*      测试类:StudentDemo*/
public class StudentDemo {public static void main(String[] args) {// 创建资源Student s = new Student();// 生产和消费的类SetThread st = new SetThread(s);GetThread gt = new GetThread(s);// 创建线程Thread t1 = new Thread(st);Thread t2 = new Thread(gt);// 启动线程t1.start();t2.start();}
}
  • 线程的等待唤醒机制:生产者有生产出来的东西,才能让消费者去消费。(没有东西可以消费时,消费者必须等待)

    • Object类中的:

      • 等待:wait()
      • 唤醒:
        • notify():唤醒单个线程
        • notifyAll():唤醒所有线程
    • 为什么这些方法不定义在Thread类中呢?
      • 这些方法的调用必须通过锁对象(可以是任意的)调用,所以必须在Object类中。
public class Student {String name;int age;boolean flag;
}public class SetThread implements Runnable{private Student s;private int x = 0;public SetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized (s){// 判断有没有生产好的if(s.flag){try {s.wait();} catch (InterruptedException e) {e.printStackTrace();}}if (x % 2 == 0){s.name = "林青霞";s.age = 27;} else {s.name = "刘意";s.age = 30;}x++;// 修改标记,并唤醒线程s.flag = true;s.notify();}}}
}public class GetThread implements Runnable{private Student s;public GetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){synchronized (s){if(!s.flag){try {s.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(s.name + "------" + s.age);// 修改标记,并唤醒线程s.flag = false;s.notify();}}}
}public class StudentDemo {public static void main(String[] args) {// 创建资源Student s = new Student();// 生产和消费的类SetThread st = new SetThread(s);GetThread gt = new GetThread(s);// 创建线程Thread t1 = new Thread(st);Thread t2 = new Thread(gt);// 启动线程t1.start();t2.start();}
}
  • 改进版

    • 将Student的成员变量私有化
    • 把设置和获取的操作封装成了功能,并同步
    • 设置和获取的线程中只需要调用方法即可
public class Student {private String name;private int age;private boolean flag;public synchronized void set(String name, int age){// 生产者:有数据就等待if (this.flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 设置数据this.name = name;this.age = age;// 修改标记this.flag = true;this.notify();}public synchronized void get(){// 消费者:没有数据就等待if(!this.flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 获取资源System.out.println(this.name + "------" + this.age);// 修改标记this.flag = false;this.notify();}
}public class SetThread implements Runnable{private Student s;private int x = 0;public SetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){if (x % 2 == 0){s.set("林青霞", 27);} else {s.set("刘意", 30);}x++;}}
}public class GetThread implements Runnable{private Student s;public GetThread(Student s){this.s = s;}@Overridepublic void run() {while(true){s.get();}}
}public class StudentDemo {public static void main(String[] args) {// 创建资源Student s = new Student();// 生产和消费的类SetThread st = new SetThread(s);GetThread gt = new GetThread(s);// 创建线程Thread t1 = new Thread(st);Thread t2 = new Thread(gt);// 启动线程t1.start();t2.start();}
}

8.线程池

  • 最麻烦的:线程池的大小

    • 压力测试
    • 并发访问测试
  • Executors工厂类:产生线程池
    • newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。(线程最大并发数不可控制);线程池为无限大,当执行第二个任务时若第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

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

      • 可以指定线程池数量

      • 可以执行Runnable或者Callable对象代表的线程

      • 调用如下方法即可

      • Future<?> submit(Runnable task)
        <T> Future<T> submit(Callable<T> task)
        public class MyCallable implements Callable {@Overridepublic Object call() throws Exception {for(int i = 0; i < 100; ++i){System.out.println(Thread.currentThread().getName() + "------" + i);}return null;}
        }public class ExcutorsDemo {public static void main(String[] args) {// 创建线程池ExecutorService pool = Executors.newFixedThreadPool(2);// 创建两个匿名的新线程传进去pool.submit(new MyRunnable());pool.submit(new MyRunnable());// 结束线程池pool.shutdown();}
        }
        
    • newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行、延迟执行。

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

public static ExecutorService newCachedThreadPool(){}
public static ExecutorService newFixedThreadPool(){}
public static ExecutorService newScheduledThreadPool(){}
public static ExecutorService newSingleThreadPool(){}
  • 匿名内部类的方式实现多线程程序

    • 创建的线程太多了,化简
    • 匿名内部类的格式
      • 本质:使该类或者接口的子类对象
new 类名或者接口名(){重写方法;
};
public class ThreadDemo {public static void main(String[] args) {// 方式1new Thread(){@Overridepublic void run() {for (int i = 0; i < 100; ++i){System.out.println(Thread.currentThread().getName() + "------" + i);}}}.start();// 方式2new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 100; ++i){System.out.println(Thread.currentThread().getName() + "------" + i);}}}).start();// 更有难度的// 两个run()执行哪个? 执行Thread的Worldnew Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 100; ++i){System.out.println("Hello" + "------" + i);}}}){@Overridepublic void run() {for (int i = 0; i < 100; ++i){System.out.println("World" + "------" + i);}}}.start();}
}
  • 定时器

    • 可用于调度多个不定时任务以后台线程的方式执行
    • 实现
      • java.util.Timer:定时器类
      • java.util.TimerTask:(抽象类)任务类
public class TimerDemo {public static void main(String[] args) {// 创建定时器对象Timer t = new Timer();// 3s后执行任务t.schedule(new MyTask(t), 3000);//        // 3s后执行任务第一次,如果不成功,每隔2s再执行一次
//        t.schedule(new MyTask(t), 3000,2000);}
}class MyTask extends TimerTask{private Timer t;public MyTask(){}public MyTask(Timer t){this.t = t;}@Overridepublic void run() {System.out.println("该任务需要执行的操作");// 任务执行完了要结束,不然会一直执行t.cancel();}
}
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;/*** 在指定的时间删除我们指定目录*/
public class DeleteDir {public static void main(String[] args) throws ParseException {Timer t = new Timer();String s = "2021-04-30 18:00:00";SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");Date d = simpleDateFormat.parse(s);t.schedule(new DeleteFolder(), d);}
}class DeleteFolder extends TimerTask{@Overridepublic void run() {File file = new File("demo");deleteFolder(file);}/*** 递归删除文件夹及其子文件夹和子文件* @param file*/public void deleteFolder(File file){File[] files = file.listFiles();if(files != null){for(File i : files){if(i.isDirectory()){deleteFolder(i);} else {System.out.println(i.getName() + "------" + file.delete());}}System.out.println(file.getName() + "------" + file.delete());}}
}

9.多线程面试题

  • sleep() 和 wait() 方法的区别

    • sleep():必须指定时间,不释放锁
    • wait():可以不指定时间,也可以指定时间,释放锁
  • run() 和 start() 的区别?
    • run():仅仅是封装需要被执行的代码,直接调用是普通方法。
    • start():首先启动了线程,然后再由JVM去调用该线程的run()。
  • java.lang.IllegalThreadStateException 非法线程状态异常?
    • 同一个线程启动两次,会报这个错误。
    • 实现多线程,需要创建两个对象,分别调用他们的start()。

Java多线程笔记(刘意day23、24)相关推荐

  1. Java多线程笔记(零):进程、线程与通用概念

    前言 不积跬步,无以至千里:不积小流,无以成江海.在学习Java多线程相关的知识前,我们首先需要去了解一点操作系统的进程.线程以及相关的基础概念. 进程 通常,我们把一个程序的执行称为一个进程.反过来 ...

  2. Java 多线程 笔记 转自http://www.cnblogs.com/lwbqqyumidi/p/3804883.html

    多线程作为Java中很重要的一个知识点, 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中 ...

  3. java多线程笔记补充之 线程控制操作

    线程休眠:让执行的线程暂停一段时间,进入计时等待状态. 方法:staticvoid sleep(long millis) 调用sleep后,当前线程放弃CPU,在指定时间段之内,sleep所在线程不会 ...

  4. 设置线程当天十二点执行_这份JAVA多线程笔记真的是细节满满,几乎全是你工作能用到的干货...

    前言 1:发挥多核CPU的优势(充分利用cpu资源) 如果是单线程的程序,那么在双核CPU上就浪费了50%,在4核CPU上就浪费了75%.单核CPU上所谓的"多线程"那是假的多线程 ...

  5. Java多线程笔记-JonHu

    多线程 文章目录 多线程 1. 几个概念 核心要点 2. 线程创建 2.1 继承Thread类(重点) 2.1.1 步骤 2.2.2 示例 2.1.3 多线程同步下载案例 2.2 实现Runnale接 ...

  6. java多线程笔记补充之线程的生命周期

    多线程通信的时候很容易造成死锁,死锁无法解决,只能避免: 当A线程等待由B线程持有的锁,而B线程正在等待A线程持有的锁时,发生死锁现象,JVM不检测也不试图避免这种情况,所以程序员必须保证不导致死锁. ...

  7. 传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)

    day24 1.多线程(JDK5之后的Lock锁的概述和使用)   Lock:           void lock(): 获取锁.           void unlock():释放锁.     ...

  8. 传智播客 刘意_2015年Java基础视频-深入浅出精华版 笔记(day01~day10)(2015年11月17日20:51:59)

    本笔记是个人笔记+摘录笔记相结合,非完全原创 day01 win 7系统打开DOS有趣方法:按住shift+右键,单击"在此处打开命令窗口"(注意:在此处可以是任何的文件夹,不一定 ...

  9. 传z播客 刘意_2015年Java基础视频笔记(day18~day20(2016年3月20日14:36:05)

    day18 1.Map引入 Map是区分于Collection的另外一个"老大" 作为学生来说,是根据学号来区分不同的学生的,那么假设我现在已经知道了学生的学号,我要根据学号去获取 ...

  10. 传z播客 刘意_2015年Java基础视频笔记(day18~day20)(2016年3月20日14:33:31)

    day18 1.Map引入 Map是区分于Collection的另外一个"老大" 作为学生来说,是根据学号来区分不同的学生的,那么假设我现在已经知道了学生的学号,我要根据学号去获取 ...

最新文章

  1. CentOS下Hive2.0.0单机模式安装详解
  2. 九章算法 | Facebook 面试题 : Backpack VI 背包算法
  3. jmeter压测前清理内存
  4. Apahce服务器配置非根目录的虚拟目录
  5. 无法鼠标拖动选择_在 iPad 上用鼠标体验怎么样?我用这 12 款 App 试了一下
  6. java程序员 英文简历_it程序员英文简历范文模板
  7. 详解如何用爬虫工具批量采集阿里巴巴批发网商品数据
  8. 仿网易评论盖楼的留言板插件demo
  9. 如何证明pi是无理数
  10. iOS打包成ipa包
  11. 微信生成二维码报invalid action name hint错误的解决方法
  12. linux系统浏览器没有图片不显示,网页不显示图片怎么回事【解决方法】
  13. 一些快捷键的用法,linux终端操作下
  14. C#创建和部署Windows Service程序
  15. datasources数据源自动配置
  16. 如何做擦能防止网站被劫持
  17. 软件项目管理的三大目标演化
  18. WINDOWS 通用杜比realtek/Dolby Audio X8560版本
  19. C++跨平台开发(VS2019+WSL(Ubuntu))
  20. 曾经有一件羽衣--名叫霓裳(转载)

热门文章

  1. 如何卸载mysql教程(按照步骤可完全卸载)
  2. Bootstrap 时间控件 datetimepicker
  3. 我的ROS学习之路——服务通信
  4. ROS机器人操作系统资料与资讯(2018年6月)
  5. matlab信号系统响应实验,信号与系统实验(MATLAB版) (1)
  6. 历年软件设计师 试卷 参考案例解析
  7. 程序员的电脑文件管理技巧
  8. 【SSM -MyBatis篇03】MyBatis Generator(MBG)配置属性详解(基于MyBatis3) - 逆向生成 - 配置MBG模板
  9. MIT算法圣经书《算法导论》第四版
  10. MIME,拓展名需要相应的软件打开