多线程
创建一个多线程的三种方式
public class Testthread {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();//第一种 继承thread
Thread threadB = new Thread(new ThreadB());//第二种 实现 Runnable
threadA.start();
threadB.start();
Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}); //第三种 匿名类
threadC.start();
}
static class ThreadA extends Thread {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
static class ThreadB implements Runnable {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
}
线程状态
线程状态大致分为新建状态、就绪状态、运行状态、阻塞状态及死亡状态。 他们之间的联系见下图:
- 新建状态 new
新建状态既创建一个线程的实例,此时还未开始运行。 - 就绪状态 runable
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 - 运行状态 running
可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序run()方法,直白点就是等待cpu调度的状态。 - 阻塞状态 blocked
阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行 以下几种方式会导致阻塞:
1.正在运行的线程通过调用sleep()方法进入等待阻塞状态,JVM会把该线程放入等待队列(waitting queue)中。
2.正在运行线程在获取对象的同步锁时,若该同步锁被别的线程占用,进入同步阻塞状态,则JVM会把该线程放入锁池(lock pool)中。
3.正在运行的线程产生了I/O请求,JVM会把线程调整为阻塞状态,等待处理完成,再次进入可运行状态。 - 死亡状态 termate
线程正常完成退出或发生异常,线程死亡。
策略模式在线程类中的应用
策略模式 本质:分离算法,选择实现 ,我们提供一个具体的策略角色AbstractClassA,它是对具体方法的抽象 ,可以由接口或抽象类完成 我们称他为抽象策略角色。 包含该策略必备的属性和方法。ClassB 和ClassC分别是策略的两种不同的策略执行角色,我们称之为具体策略角色,是对策略的实现。ClassD 是用来操作策略的角色,其职责本来是隔离客户端与策略类的耦合,让客户端完全与上下文环境沟通,无需关系具体策略,其被称为上下文角色,ClassD 内部一定会有一个策略类的一个成员变量(AbstractClassA),当我们需要实现具体的策略时,可以向ClassD中传入具体的策略的实现类,执行具体的策略。
public abstract class AbstractClassA {
/*
* 获取一个名字
* */
public abstract String getname(String str);
}
class ClassB extends AbstractClassA{
@Override
public String getname(String str) {
return str;
}
}
class ClassC extends AbstractClassA{
@Override
public String getname(String str) {
return "hello world";
}
}
final class ClassD {
private AbstractClassA a;
ClassD(){
}
ClassD(AbstractClassA a){
this.a=a;
}
String getname(String str)
{
if(a!=null)
return a.getname(str);
return null;
}
}
class ClassE{
public static void main(String[] args) {
String name = "xiaoming";
ClassD D = new ClassD();
/*此时是未使用任何抽象类的 直接调用的我们ClassD的getname方法 */
System.out.println(D.getname(name));
ClassC c = new ClassC();
/*我们给ClassD中传入一个AbstractClassA 我们就可以自由的对AbstractClassA的getname方法进行实现*/
ClassD D1 = new ClassD(c);
System.out.println(D1.getname(name));
ClassB b = new ClassB();
ClassD D2 = new ClassD(b);
System.out.println(D2.getname(name));
}
}
> 回过头我们再看thread类,thread中包含一个Runnable接口的抽象策略角色,而我们具体去实现Runnable的run方法时,我们就自己去实现了一个具体策略角色,thread类被定义为上下文类。其run方法通过构造方法传入具体的策略角色进行实现run方法。
``` java
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
public
class Thread implements Runnable {
/* What will be run. */
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target; //将具体策略类传入
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();//调用c++ 的start0 c++再执行java的run方法
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
@Override
public void run() {
if (target != null) {
target.run(); //执行策略类的run方法
}
}
}
我们看到当我们实例化一个thread时,无论是那个构造函数最终都会调用private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) 这个方法,其中有个stacksize表示创建线程所使用的栈的大小,如果为传入的话,默认会由jni的c++ 自动初始化,我们通常不会使用这个参数,如果一定要使用,会通过直接设置java 的栈参数指定 -Xss<size> 指定java线程的栈大小。
守护线程
守护线程会随着主线程的消亡而就是当进程不存在或主线程停止,守护线程也会被停止。
public class Testthread {
public static void main(String[] args) {
ThreadA threadA = new ThreadA();//第一种 继承thread
threadA.setDaemon(true);//设定为守护线程 必须在start之前调用
threadA.start();
}
static class ThreadA extends Thread {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
}
线程优先级
线程优先级通过设置一个 thread.setPriority(int newpriority)使该线程具有较高的优先级,cpu会优先分配资源给该线程。(不代表一定会优先执行) 范围是0-10 默认是5.
public class Testthread {
public static void main(String[] args) throws Exception {
ThreadA threadA = new ThreadA();
Thread threadB = new Thread(new ThreadB(),"thread-B");
threadA.setName("thread-A");
threadA.setPriority(1);
threadA.start();
//threadA.setDaemon(true);
threadB.setPriority(3);
threadB.start();
Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
},"thread-C");
threadC.setPriority(2);
threadC.start();
//threadB.join();
//threadC.join();
System.out.println(java.lang.Thread.currentThread().getName());
}
static class ThreadA extends Thread {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
static class ThreadB implements Runnable {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
}
/**
*执行结果
*main
*这是一个线程thread-A
*这是一个线程thread-C
*这是一个线程thread-B
*/
thread.join()
join方法的作用是父线程等待所有join的线程都执行完成后,才能继续用下运行 有join() ,join(long),join(long,int) 三种 。
- join() 等待所加入的线程完全执行完成。
- join(long) 等待所加入的线程一段时间(毫秒) ,如果还未完成,父线程继续执行。
- join(long,int)同上 精度更高 例如join(1000,10) 1000毫米10纳秒
public class Testthread {
public static void main(String[] args) throws Exception {
ThreadA threadA = new ThreadA();
Thread threadB = new Thread(new ThreadB(),"thread-B");
threadA.start();
//threadA.setDaemon(true);
threadB.start();
Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
});
threadC.start();
threadB.join();
threadC.join();//主线程main会等待线程B和线程C执行完成再执行
System.out.println(java.lang.Thread.currentThread().getName());
}
static class ThreadA extends Thread {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
static class ThreadB implements Runnable {
@Override
public void run() {
System.out.println("这是一个线程"+ Thread.currentThread().getName());
}
}
}
--没有join
main
这是一个线程Thread-0
这是一个线程Thread-1
这是一个线程Thread-2
--有join
这是一个线程Thread-0
这是一个线程Thread-1
这是一个线程Thread-2
main
*NOTE: Thread.currentThread().join() 可以用来阻塞自己,线程一直在等自己死亡执行结束。
中断
中断在方法在线程中包含5个方法,interrupt(),isInterrupted(boolean),isInterrupted(),interrupt0()和interrupted()。他在中断 sleep wait join方法时会抛InterruptedException异常。
- interrupt()设置为中断状态,不能真的中断线程。
- interrupted() 当前线程设置中断状态
- isInterrupted(boolean)可以修改中断状态 私有方法
- isInterrupted() 返回中断状态
private native void interrupt0(); //私有方法
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
public boolean isInterrupted() {
return isInterrupted(false);
}
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
private native boolean isInterrupted(boolean ClearInterrupted);//私有方法
结束线程
我们知道在线程中,stop()方法存在安全问题,suspend()会发生死锁, 那么我们应该如何正确的结束一个线程呢,首先, 我们可以想到 ,守护线程会随着父线程的消亡而消亡,那么就可以把要执行的程序设置为某一父线程的守护线程,我们想办法让他的父线程停止,守护线程就随之停止了,然后,当我们中断一个线程时,被中断的线程在调用 wait sleep join 等方法时会抛出InterruptedException异常,终止当前线程,我们可以利用这个原理,中断守护线程的父线程。达到停止我们要执行的任务的目的。
public class Threadinterrupt {
public static void main(String[] args) {
Threadservice threadservice = new Threadservice();
threadservice.exec(()->{
while (true){
System.out.println("正在执行线程"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
try {
Thread.sleep(5000);
threadservice.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Threadservice{
private Thread thread;
void exec(Runnable runnable)
{
if(thread==null)
thread = new Thread(()->{
Thread threadinner = new Thread(runnable);
/*设定为守护线程*/
threadinner.setDaemon(true);
threadinner.start();
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
}
void stop()
{
/*调用*/
if(thread!=null&& thread.isAlive())
thread.interrupt();
System.out.println("中断守护线程的父线程");
}
}
CountDownLatch
CountDownLatch是一个同步工具类 可以理解为线程同步计数器
public class countdownlatchdemo{
CountDownLatch c = new CountDownLatch(10);
for (int i=0; i<9; i++) {
new Thread(()->{
c.countDown()
System.out.println(Thread.currentThread().getThreadID);
}).start();
}
c.await()
}