创建线程-学到了4中方法

  • 线程创建的4种方法VS线程安全的3种方法
    • 程序,进程,线程
      • 并行与并发
  • 一.多线程的创建4种方法
    • 1.多线程的创建方式一:继承Thread类
      • Thread中常用的方法
    • 2.多线程的创建方式二:实现Runnable接口
    • 比较创建线程的两种方式:(继承Thread类和实现Runnable接口)
    • 线程的分类
    • 多线程实例:龟兔赛跑
    • JDK5.0新增2种线程创建方式
    • 3.多线程的创建方式三:实现Callable接口
    • 4.多线程的创建方式四:使用线程池
    • 线程的声明周期:
  • 二.解决线程安全的3种方法:
    • 方式一:同步代码块
    • 方式二:同步方法
      • 1.实现Runnable接口的同步方法
      • 2.继承Thread类的同步方法
      • 单例模式-----懒汉式的线程安全问题
      • 死锁
    • 方式三:lock锁--------JDK5.0新增
      • 1.面试题:synchronized 与 Lock的异同?
      • 2.面试题:如何解决线程安全问题?有几种方法?
    • 线程通信
      • 3.面试题:sleep()和wait()的异同?
      • 经典例题:生产者/消费者问题

线程创建的4种方法VS线程安全的3种方法

程序,进程,线程

  • 程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期

如:运行中的QQ,运行中的MP3播放器
程序是静态的,进程是动态的
进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域(方法区和堆空间)

  • 线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径

若一个进程同一时间并行执行多个线程,就是支持多线程的
线程作为调度和执行的单位,每个线程拥有独立的运行程序计数器(pc),线程切换的开销小
一个进程中的多个线程共享相同的内存单元/内存地址空间(方法区和堆空间)→它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患

进程是系统资源分配的基本单位,线程是任务调度和执行的基本单位

单核CPU和多核CPU:

单核CPU:其实是一种假的多线程,时间单元内只能执行一个线程任务。一个人同时炒3个菜(并发)。
多核CPU:3个人同时炒3个菜(并行) (现在的服务器都是多核的)

一个Java应用程序java.exe,其实至少有三个线程: main()主线程,gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。

并行与并发

并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。
并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事。

多线程程序的优点:
1.提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
2.提高计算机系统CPU的利用率
3.改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改

何时需要多线程?

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
  • 需要一些后台运行的程序时。

一.多线程的创建4种方法

1.实现Runnable接口(常用)
2.继承Thread类
3.实现Callable接口

1.多线程的创建方式一:继承Thread类

步骤:
1.创建一个继承于Thread类的子类
2.重写Thread类的run() -->此线程执行的操作声明在run()中
3.创建Thread类的子类的对象
4.通过此对象调用start()方法

start()方法的作用:①启动当前线程 ②调用当前run()方法

代码练习:创建两个分线程,遍历100以内的偶数

public class MyThread extends Thread {  //1.继承Thread@Overridepublic void run() {  //2.重写run()方法for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName()+":"+i);}}}
}
class ThreadTest{public static void main(String[] args) {//3.创建对象MyThread myThread1 = new MyThread();  //创建线程1的对象MyThread myThread2 = new MyThread();  //创建线程2的对象//4.通过对象调start()方法myThread1.start();  //启动线程1myThread2.start();  //启动线程2//如下操作仍然是在main线程中执行的System.out.println(Thread.currentThread().getName()+"今天星期五!");}
}
main今天星期五!
Thread-0:0
Thread-0:2
Thread-0:4
Thread-0:6
Thread-1:0
Thread-0:8

问题一:我们不能通过直接调用run()的方式启动线程-------启动线程只能用对象.start()

问题二:再启动一个线程,遍历100以内的偶数?
我们需要重新创建一个线程的对象,然后对象调用start() (多个线程就创建多个对象)

代码练习2:创建两个分线程,其中一个遍历100以内的偶数,另外一个遍历100以内的奇数。
分析:此时两个线程执行的任务不同,故需要创建两个继承于Thread的子类

方法一:

class MyThread01 extends Thread {   //偶数线程@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName()+":" + i);}}}
}
class MyThread02 extends Thread {  //奇数线程@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 != 0) {System.out.println(Thread.currentThread().getName()+":" + i);}}}
}
public class ThreadDemo {public static void main(String[] args) {//3.创建对象MyThread01 myThread01 = new MyThread01();MyThread02 myThread02 = new MyThread02();//4.对象调用start()方法myThread01.start();myThread02.start();}
}

方法二:匿名子类—>是创建thread类的匿名子类

public class ThreadDemo {public static void main(String[] args) {new Thread(){@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 == 0) {System.out.println(Thread.currentThread().getName()+":" + i);}}}}.start();new Thread(){@Overridepublic void run() {for (int i = 0; i < 100; i++) {if (i % 2 != 0) {System.out.println(Thread.currentThread().getName()+":" + i);}}}}.start();}
}

执行结果:两个线程按CPU时间片轮流执行

Thread-0:0
Thread-0:2
Thread-0:4
Thread-0:6
Thread-0:8
Thread-0:10
Thread-0:12
Thread-0:14
Thread-0:16
Thread-0:18
Thread-1:1
Thread-1:3
Thread-1:5
Thread-1:7
Thread-1:9
Thread-1:11
Thread-1:13
Thread-1:15
Thread-1:17
Thread-1:19
Thread-1:21
Thread-1:23

Thread中常用的方法

  • void start(): 使该线程开始执行;Java 虚拟机调用该线程的 run 方法
  • run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中。
  • string getName():返回线程的名称
  • void setName(String name):设置该线程名称
  • static Thread currentThread():返回对当前正在执行的线程对象的引用。在Thread子类中就是this,通常用于主线程和Runnable实现类
  • static void yield():线程让步

暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程>若队列中没有同优先级的线程,忽略此方法

  • join():(让别的线程插到自己前面)当某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到join()方法加入的 join 线程执行完为止

低优先级的线程也可以获得执行

  • static void sleep(long millis):(指定时间:毫秒)

令当前活动线程在指定时间段内放弃对CPPJ控制,使其他线程有机会被执行,时间到后重排队。
抛出InterruptedException异常

  • stop():强制线程生命期结束,不推荐使用
  • boolean `isAlive():返回boolean,判断线程是否还活着

2.多线程的创建方式二:实现Runnable接口

步骤:
1.创建一个实现Runnable接口
2.实现类去实现Runnable中抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()

package com.guo;
//多线程同时操作同一对象
//买火车票的例子
//发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread04 implements Runnable{//票数private int tickeNums=10;public void run() {while(true){if (tickeNums<=0){break;}try {Thread.sleep(200);//线程睡眠200毫秒(暂停执行 )} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickeNums--+"张票");}}public static void main(String[] args) {TestThread04 t4 = new TestThread04();//线程并发运行new Thread(t4,"学生").start();new Thread(t4,"老师").start();new Thread(t4,"黄牛党").start();}
}

运行结果

com.guo.TestThread04
学生-->拿到了第10张票
老师-->拿到了第9张票
黄牛党-->拿到了第8张票
黄牛党-->拿到了第7张票
老师-->拿到了第6张票
学生-->拿到了第5张票
黄牛党-->拿到了第4张票
老师-->拿到了第3张票
学生-->拿到了第2张票
老师-->拿到了第1张票
黄牛党-->拿到了第0张票
学生-->拿到了第-1张票Process finished with exit code 0

发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱

比较创建线程的两种方式:(继承Thread类和实现Runnable接口)

开发中:优先选择:实现Runnable接口的方式
原因:

  1. 实现的方式没有类的单继承性的局限性
  2. 实现的方式更适合来处理多个线程有共享数据的情况

两者的联系: Thread也实现了Runnable
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。
目前两种方式,要想启动线程,都是调用的Thread类中的start()。

线程的分类

多线程实例:龟兔赛跑

package com.guo;
//模拟龟兔赛跑
public class Race implements Runnable{//胜利者private static String winner;public void run() {for (int i = 0; i <= 100; i++) {//模拟兔子休息if (Thread.currentThread().getName()=="兔子"&& i%10==0){ //兔子每走10步休息10mstry {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}//判断比赛是否结束if (gameOver(i)){break;}System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");}}//判断是否完成比赛private boolean gameOver(int steps){if (winner!=null){return true;}else if (steps>=100){winner = Thread.currentThread().getName();System.out.println("winner is"+winner);return true;}else {return false;}}public static void main(String[] args) {Race race = new Race();new Thread(race,"兔子").start();new Thread(race,"乌龟").start();}
}
乌龟-->跑了0步
乌龟-->跑了1步
乌龟-->跑了2步
乌龟-->跑了3步
乌龟-->跑了4步
乌龟-->跑了5步
乌龟-->跑了6步
乌龟-->跑了7步
乌龟-->跑了8步
乌龟-->跑了9步
乌龟-->跑了10步
乌龟-->跑了11步
乌龟-->跑了12步
乌龟-->跑了13步
乌龟-->跑了14步
乌龟-->跑了15步
乌龟-->跑了16步
乌龟-->跑了17步
乌龟-->跑了18步
乌龟-->跑了19步
乌龟-->跑了20步
乌龟-->跑了21步
乌龟-->跑了22步
乌龟-->跑了23步
乌龟-->跑了24步
乌龟-->跑了25步
乌龟-->跑了26步
乌龟-->跑了27步
乌龟-->跑了28步
乌龟-->跑了29步
乌龟-->跑了30步
乌龟-->跑了31步
乌龟-->跑了32步
乌龟-->跑了33步
乌龟-->跑了34步
乌龟-->跑了35步
乌龟-->跑了36步
乌龟-->跑了37步
乌龟-->跑了38步
乌龟-->跑了39步
乌龟-->跑了40步
乌龟-->跑了41步
乌龟-->跑了42步
乌龟-->跑了43步
乌龟-->跑了44步
乌龟-->跑了45步
乌龟-->跑了46步
乌龟-->跑了47步
乌龟-->跑了48步
乌龟-->跑了49步
乌龟-->跑了50步
乌龟-->跑了51步
乌龟-->跑了52步
乌龟-->跑了53步
乌龟-->跑了54步
乌龟-->跑了55步
乌龟-->跑了56步
乌龟-->跑了57步
乌龟-->跑了58步
乌龟-->跑了59步
乌龟-->跑了60步
乌龟-->跑了61步
乌龟-->跑了62步
乌龟-->跑了63步
乌龟-->跑了64步
乌龟-->跑了65步
乌龟-->跑了66步
乌龟-->跑了67步
乌龟-->跑了68步
乌龟-->跑了69步
乌龟-->跑了70步
兔子-->跑了0步
乌龟-->跑了71步
兔子-->跑了1步
乌龟-->跑了72步
兔子-->跑了2步
乌龟-->跑了73步
乌龟-->跑了74步
乌龟-->跑了75步
乌龟-->跑了76步
乌龟-->跑了77步
乌龟-->跑了78步
乌龟-->跑了79步
乌龟-->跑了80步
乌龟-->跑了81步
乌龟-->跑了82步
乌龟-->跑了83步
乌龟-->跑了84步
乌龟-->跑了85步
乌龟-->跑了86步
乌龟-->跑了87步
乌龟-->跑了88步
乌龟-->跑了89步
乌龟-->跑了90步
乌龟-->跑了91步
乌龟-->跑了92步
乌龟-->跑了93步
乌龟-->跑了94步
乌龟-->跑了95步
乌龟-->跑了96步
乌龟-->跑了97步
乌龟-->跑了98步
乌龟-->跑了99步
winner is乌龟
兔子-->跑了3步Process finished with exit code 0

JDK5.0新增2种线程创建方式

3.多线程的创建方式三:实现Callable接口



步骤:

  1. 实现Callable接口
  2. 重写Call方法
  3. 创建Callable接口实现类的对象
  4. 将此Callable接口实现类的对象作为参数传递到FutureTask构造器,创建FutureTask的对象
  5. 将FutureTask的对象作为阐述传递到Thread类的构造器中,创建Thread对象,并调用start()
  6. futureTask.get()//获取Callable中的call方法的返回值

4.多线程的创建方式四:使用线程池

步骤:

  1. 提供指定线程数量的线程池
  2. 执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
  3. 关闭连接池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;//创建线程
class ThreadRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {if (i % 2 == 0) {   System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}
public class ThreadPool {public static void main(String[] args) {// 1. 提供指定线程数量的线程池ExecutorService service = Executors.newFixedThreadPool(10);ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;//设置线程池的属性System.out.println(service.getClass()); //class java.util.concurrent.ThreadPoolExecutor//service1.setCorePoolSize(15);//2. 执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象service.execute(new ThreadRunnable()); //适合于Runnable
//        service.submit();//适用于Callable//3. 关闭连接池service.shutdown();}
}

接口中属性都是常量,设置属性需要找到实现类,设置类中的属性
class java.util.concurrent.ThreadPoolExecutor


获取系统时间

 //获取当前系统时间Date starTime = new Date(System.currentTimeMillis());//获取系统当前时间while (true){Thread.sleep(1000);System.out.println(new SimpleDateFormat("HH:mm:ss").format(starTime));starTime = new Date(System.currentTimeMillis());//更新系统时间}

10秒倒计时

 public static void tenDown() throws InterruptedException {int num = 10;while (true){Thread.sleep(1000);System.out.println("倒计时:"+num--);if (num<=0){break;}}}

线程的声明周期:

新建,就绪,运行,阻塞,死亡

二.解决线程安全的3种方法:

  1. 发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
  2. 问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票
  3. 如何解决:当一个线程a在操作车票的时候,其他线程不能参与进来,直到线程a操作完车票时,其他线程才可以开始操作车票。(线程排队一个一个来)
  4. 在Java中,我们通过同步机制,来解决线程的安全问题

方式一:同步代码块

synchronized(同步监视器){//需要被同步的代码
}

说明:

  1. 操作共享数据的代码,就是需要被同步的代码 -----不能包含代码多了,也不能包含代码少了
  2. 共享数据:多个线程共同操作的变量,比如我们的车票数tickeNums
  3. 同步监视器,俗称:锁。任何对象都可以充当这个锁
    要求:多个线程必须要共用同一把锁

  1. 同步的方式,解决了线程的安全问题。 ----好处
  2. 操作同步代码时,只能一个线程参与,其他线程等待,相当于是一个单线程的过程,效率低----坏处

方式二:同步方法

如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

1.实现Runnable接口的同步方法

2.继承Thread类的同步方法


总结:

  1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
  2. 非静态的同步方法,同步监视器是:this
  3. 静态的同步方法,同步监视器是:当前类本身

单例模式-----懒汉式的线程安全问题

普通的懒汉式----存在线程安全,可能会创建多个实例

//单例模式----懒汉式
class Bank {private void Bank() {}private static Bank instance = null;public static Bank getInstance() {if (instance == null) {instance = new Bank();}return instance;}
}

通过添加synchronized(同步代码块),使得懒汉式线程安全


//单例模式----懒汉式
class Bank {private void Bank() {}private static Bank instance = null;public static Bank getInstance() {//方式一:效率稍差synchronized (Bank.class) {if (instance == null) {instance = new Bank();}return instance;}}
}

懒汉式线程安全优化】缩小synchronized代码块的范围,使得第一个创建对象的时候需要进入同步块,后边的线程就不需要排队进入同步代码块了,这样大大缩短了同步所浪费的时间

//单例模式----懒汉式
class Bank {private void Bank() {}private static Bank instance = null;public static Bank getInstance() {//方式二:效率更高if (instance == null) {synchronized (Bank.class) {instance = new Bank();}}return instance;}
}

死锁

资源互斥
占有且等待
资源不可剥脱
循环等待

方式三:lock锁--------JDK5.0新增

步骤:

  1. 实例化ReentrantLock
  2. 调用锁定方法lock()
  3. 调用解锁方法:unlock()
import java.util.concurrent.locks.ReentrantLock;class TestThread04 implements Runnable {//票数private int tickeNums = 10;//1.实例化ReentrantLockprivate ReentrantLock lock = new ReentrantLock();public void run() {while (true) {try {//2.调用锁定方法lock()lock.lock();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}if (tickeNums > 0) {System.out.println(Thread.currentThread().getName() + "-->拿到了第" + tickeNums-- + "张票");} else {break;}} finally {//3.调用解锁方法:unlock()lock.unlock();}}}public static void main(String[] args) {TestThread04 t4 = new TestThread04();//线程并发运行new Thread(t4, "学生").start();new Thread(t4, "老师").start();new Thread(t4, "黄牛党").start();}
}

1.面试题:synchronized 与 Lock的异同?

相同点:都可以解决线程安全问题
不同点:

  1. synchronized机制在执行完响应的同步代码以后,自动的释放同步监视器
  2. Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())

2.面试题:如何解决线程安全问题?有几种方法?

  1. synchronized同步代码块
  2. synchronized同步方法
  3. lock锁

线程通信

线程通信的例子:使用两个线程打印1-100。线程1,线程2 交替打印

涉及到三个方法

  1. wait():阻塞当前线程,并释放同步监视器
  2. notify():唤醒被wait的一个线程, 如果有多个被wait的线程,就唤醒优先级高的线程
  3. notifyAll():唤醒所有被wait()的线程

说明:

  1. wait() , notify() , notifyAll()三个方法必须使用在同步代码块或同步方法中。

  2. wait() , notify() , notifyAll()三个方法的调用者,必须是同步代码块或同步代码方法中的同步监视器。

  3. 否者,会出现异常

  4. wait() , notify() , notifyAll()三个方法是定义在java.lang.Object类中。

    线程通信的例子:使用两个线程打印1-100。线程1,线程2 交替打印

class Number01 implements Runnable {private int number = 1;@Overridepublic void run() {while (true) {synchronized (this) {    //默认当前类作为同步监视器this.notify();if (number <= 100) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":" + number++);try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}}}
}
public class CommunicationTest {public static void main(String[] args) {Number01 number01 = new Number01();new Thread(number01,"线程1").start();new Thread(number01,"线程2").start();}
}

打印结果

线程1:1
线程2:2
线程1:3
线程2:4
线程1:5
线程2:6
线程1:7
线程2:8
线程1:9
线程2:10
...

3.面试题:sleep()和wait()的异同?

  1. 相同点:都可以使得当前线程进入阻塞状态
  2. 不同点:
    ①两个方法声明的位置不同,Thread类中声明sleep(),Object类中声明wait()
    ②调用的要求不同:sleep()可以在任何需要的场景下调用,wait()必须使用在同步代码块或同步方法中
    ③关于是否释放同步监视器的问题:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁

经典例题:生产者/消费者问题

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

分析:
1.多线程问题:生产者线程,消费者线程
2.共享数据:店员(产品)
3.线程安全:使用同步机制(线程安全的3种方法)
4.通信问题:wait() notify() notifyAll()

//店员
class Clerk {private int productCount = 0; //产品的个数//生产产品public synchronized void produceProduct() {  //同步监听器thisif (productCount < 20) {productCount++;System.out.println(Thread.currentThread().getName() + ":生产了第" + productCount + "个产品");notify();} else { //等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}//消费产品public synchronized void consumerProduct() { //同步监听器thisif (productCount > 0) {System.out.println(Thread.currentThread().getName() + ":消费了第" + productCount + "个产品");productCount--;notify();} else {//等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}}//生产者
class Producer implements Runnable {private Clerk clerk;public Producer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始生产产品......");while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}clerk.produceProduct();}}
}//消费者
class Consumer implements Runnable {private Clerk clerk;public Consumer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始消费产品......");while (true) {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}clerk.consumerProduct();}}
}public class ProductTest {public static void main(String[] args) {Clerk clerk = new Clerk();Producer p1 = new Producer(clerk);new Thread(p1, "生产者1").start();Consumer c1 = new Consumer(clerk);new Thread(c1, "消费者1").start();}
}

运行结果:

生产者1开始生产产品......
消费者1开始消费产品......
生产者1:生产了第1个产品
生产者1:生产了第2个产品
消费者1:消费了第2个产品
生产者1:生产了第2个产品
消费者1:消费了第2个产品
生产者1:生产了第2个产品
生产者1:生产了第3个产品

创建线程-学到了4种方法相关推荐

  1. 线程间通信的三种方法 (转)

    http://www.cnblogs.com/puxidun/archive/2009/12/06/1618142.html 线程间通信的三种方法 多线程通信的方法主要有以下三种:  1.全局变量 进 ...

  2. 想不到吧,Java创建线程的方式只有一种

    目录 前言 继承Thread方式 实现Runnable接口 实现callable接口 总结 前言 看到这个标题的小伙伴先别着急喷我--在面试的时候,我们经常会被问到这种基础题:Java创建线程的方式有 ...

  3. 创建线程池有哪几种方式呢?

    转自: 创建线程池有哪几种方式呢? 下文笔者讲述创建线程池的方法分享,如下所示 java原生提供创建线程池的方式如下 newSingleThreadExecutor():它的特点在于工作线程数目被限制 ...

  4. ABAP中创建动态内表的三种方法(转载)

    BAP中创建动态内表的三种方法 第一种: 如果我们需要的动态内表字段或者动态工作区和数据字典中的类型一致,可以直接使用CREATE DATA生成,当然也可以是自定义类型. 比如要产生和数据表MARA结 ...

  5. JDK1.8 创建线程池有哪几种方式?

    JDK1.8 创建线程池有哪几种方式? newFixedThreadPool 定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会 ...

  6. 教你学Java | 带你学习Java多线程(续:创建线程的其他方式与activeCount方法的浅谈)

    前言 相信每一位程序猿对"多线程"这个概念应该都不陌生,无论是在开发还是面试的时候,都会遇到多线程的问题.不过,一定有很多小伙伴才刚刚接触到多线程,那么在此就由小弟为各位小伙伴细细 ...

  7. 创建线程(Background Thread)的N种方式

    第一.Thread类 Thread类是实例化线程的主要方法:一个Thread实例管理一个线程,即执行序列.通过简单实例化一个对象,就可以创建一个线程,然后通过Thread对象提供的方法对线程进行管理. ...

  8. 线程间同步的几种方法--互斥锁,条件变量,信号量,读写锁

    一.互斥锁(mutex) 锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 1 . 初始化锁 int pthread_mutex_init(pthread_mutex_t *mutex,cons ...

  9. 线程之间传递信息的几种方法 Android

    一.需求分析 在使用okhttp的时候,有时会遇到需要在onresponse中将数据传送到其他线程中,或者是发送消息给UI线程,通知其更改UI的情况,并且我想返回的数据不是普通数据,而是一个类的对象. ...

  10. android线程间通信的几种方法_Android线程间通信机制

    讲解Handler机制的博文很多,我也看了很多,但说实话,在我对Handler几乎不怎么了解的情况下,每一篇文章我都没太看懂,看完之后脑子里还是充满了疑问.究其原因,是因为几乎每一篇文章一上来就开始深 ...

最新文章

  1. GXGetImage方式连续采集和发送软触发采集
  2. 对话图灵奖得主John Hennessy,他说对美国留学签证变化很忧心
  3. leeds计算机科学理学硕士,利兹大学数学及计算机科学理学硕士研究生申请要求及申请材料要求清单...
  4. php怎么爬取亚马逊的数据,使用PHP从Amazon MWS API获取订单数据
  5. 图像压缩哪家强?请看这份超详细对比
  6. 网页调用摄像头_【WebAR】虚拟现实来到网页——WebXR Device API第二部分
  7. 《C语言点滴》一1.5 内功修炼
  8. 找不到 javax.servlet.http.HttpServletResponse 和 javax.servlet.http.HttpServletRequest 问题解决...
  9. 赛尔原创 | N-LTP:基于预训练模型的中文自然语言处理平台
  10. 【从入门到放弃-Java】并发编程-NIO-Buffer
  11. android 电视遥控 编程,Android编程调用红外线遥控功能示例
  12. cocos2d-x学习(一) HelloWorld
  13. SwiftUI资源列表
  14. 做柜员还是程序员_未来的程序员,还是“高薪一族”吗?
  15. 用java计算定积分
  16. ElasticSearch学习总结2(基础查询)
  17. 环境影响评价概论期末试题重点考点
  18. LTE上行物理层传输机制(6)-周期CQI、PMI和RI的发送时机
  19. 利用PS的磁性套索工具进行抠图
  20. 【大厂面试】智力题怎么破?

热门文章

  1. mysql got error 1045_mysqldump 备份的问题Got error: 1045、ERROR 1045 (28000)、Got error: 1449
  2. 8g内存一般占用多少_你到底需要多大内存?4G、8G还是16G
  3. 1:n的冗余备份_备份与冗余:有什么区别?
  4. jetlinks之Thing(六)
  5. Docker学习中文文档大全、dockerdocker-compose实战
  6. Verilog语言乒乓球机8段译码器
  7. python 序列类型是二维元素向量,测验6: 组合数据类型 (第6周)
  8. 基于php+MySQL的个人网站的设计与实现
  9. 电容之超级电容简易测试方法
  10. 磁盘阵列RAID卡组建设置