多线程(一) 基础
一、定义
程序:是为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态代码,对象。
进程:是程序执行一次的过程,正在运行的一个程序。动态过程:有他自身产生,存在,消亡的过程
线程:程序内部的一条执行入径。
二、优点
背景:只使用单个线程完成多个任务(调用多个方法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?
优点:
- 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
- 提高计算机系统CPU的利用率
- 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改
三、线程的创建方式
3.1 继承Thread重写run()方法
1 2 3 4 5
| class A extends Thread{ @Override public void run(){ } }
|
3.2 实现Runnable接口的run方法,推荐
不影响类的继承。因为类是单继承的。
针对于有共享数据的操作,更适合使用Runnable的方式。换句话说,实现Runnable接口的方式,实现了代码和数据的分离。
java8 之后 lambda表达式的加入更是花里胡哨
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
|
public class TestA {
@Test public void run() throws InterruptedException { new Thread(new A()).start(); Runnable runnable = new Runnable() { @Override public void run() { System.out.println("hello"); } }; new Thread(runnable).start(); Runnable runnable1 = ()-> System.out.println("hello"); new Thread(runnable1); new Thread(()-> System.out.println("")).start(); new Thread(B::run).start(); } }
class A implements Runnable{ @Override public void run(){ } }
class B { public static void run(){ System.out.println("da"); } }
|
3.3 通过线程池中获取 这种也是推荐的
实现 ThreadFactory 接口,实现 newThread 方法
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
|
public class NameThreadFactory implements ThreadFactory { private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix;
private NameThreadFactory() { this("default-name-pool"); }
private NameThreadFactory(String name){ SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = name + POOL_NUMBER.getAndIncrement(); }
@Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + "-thread-"+threadNumber.getAndIncrement(), 0); if (t.isDaemon()){ t.setDaemon(false); } if (t.getPriority() != Thread.NORM_PRIORITY){ t.setPriority(Thread.NORM_PRIORITY); } return t; }
public static NameThreadFactory build(){ return new NameThreadFactory(); }
public static NameThreadFactory build(String name){ return new NameThreadFactory(name); }
}
|
四、Thread类的常用方法
- run():Thread的子类一定要重写的方法。将此分线程要执行的操作,声明在run()中
- start():要想启动一个分线程,就需要调用start():①启动线程②调用线程的run()
- currentThread():静态方法,获取当前的线程
- getName():获取当前线程的名字
- setName(String name):设置当前线程的名字
- yield():当前线程调用此方法,释放CPU的执行权
- join():在线程a中调用线程b的join()方法:只用当线程b执行结束以后,线程a结束阻塞状态,继续执行。
- sleep(long millitimes):让当前的线程睡眠millitimes毫秒
- isAlive():判断当前线程是否存活
五、线程的生命周期
新生态:刚创建
就绪态:调用了start
运行态: 抢到了Cpu执行时间
阻塞态:线程失去了Cpu执行时间
- 等待队列:调用了wait()方法
- 锁池:等待锁标记
死亡态:线程执行完毕

六、线程的优先级
线程调用 setPriority(int i) 设置优先级。
设置线程的优先级只是修改这个线程可以抢到Cpu执行时间的一个概率,并不能保证优先级高的一定比优先级低的先执行。
优先级的设置是一个整数,【0,10】区间内,默认是5
优先级的设置必须放到执行之前
七、线程的礼让
指的是让当前运行的线程释放自己的cpu资源,由运行状态回到就绪状态。
线程调用yield() 方法释放自己的cpu资源。
八、线程的分类
Java中的线程分为两类:一种是守护线程,一种是用户线程
8.1 守护线程
Java中的线程分为两类:一种是守护线程,一种是用户线程
- 它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
- 守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
- Java垃圾回收就是一个典型的守护线程
- 若JVM中都是守护线程,当前JVM将退出