Java 线程

线程(Thread)

在一个java程序运行时,就有线程被调用。如果没有在程序中建立线程,那么在运行main() 方法的时候,JVM 就会启用一条线程来执行该 Java 程序,这条被唤醒执行 main() 方法的线程就是主线程。

线程的创建和运行

在使用之前一定要明白:在Java中说有的线程都是通过 java.lang.Thread 来创建并被 Thread 类所控制。通过调用 Thread 类的构造函数就可以在主线程之外创建一条新线程。

	Thread t = new Thread();

在通过调用 Thread 类中的 start() 方法来启动这条线程,即:t.start();

java.lang.Thread

如果仅仅只是按照上面的方法来创建一个新的线程,那么这条线程什么都做不了。这样完全没有任何意义,所以我们可以通过继承的方式来实现创建一个新的Thread class来完成我们的自定义任务。

public class MyThread extends Thread {

	// 我们把要执行的任务代码写在 run() 方法中
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + " 我是普通的用户线程");
		System.out.println("Hello world!");
	}

	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName() + " 我是主线程");
		
		System.out.println("创建线程");
		Thread thread = new MyThread();
	
		System.out.println("开始线程");
		thread.start();
	}
}

Thread.currentThread() 返回当前的线程;getName() 返回线程名称

// 输出
main 我是主线程
创建线程
开始线程
Thread-0 我是普通的用户线程
Hello world!

java.lang.Runnable

通过源码我们能够发现 Thread 也是调用 Runnable 接口来实现 run() 方法

	// 源码
	// public class Thread implements Runnable
	private Runnable target;
	@Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

那为什么在查资料时,看见使用Runnable重构 run 方法的要比 直接调用Thread还要多呢?
因为,Thread是一个类,而在 Java 中只允许单继承,这样就很有局限性:如新建了一个类,既想要继承其他的类,又想实现多线程操作,而父类只能有一个,在这时候就可以通过 implements 接口的方式来实现对一个类的拓展。(在Runnable接口中,只有一个 run() 方法)。 实现如下:

public class MyRunnable implements Runnable {

	@Override
	public void run() {
			System.out.println(Thread.currentThread().getName() + ": 我是普通的用户线程");
	}
	
	public static void main(String[] args) {		
		System.out.println("创建线程");
		Thread thread = new Thread(new MyRunnable());
	
		System.out.println("开始线程");
		thread.start();
	}
}	

线程的中断

线程的结束与否由该线程自己决定。
过去常用 stop 方法来结束线程,即线程从外部 kill 的话。这样操作容易导致线程执行中所占用的资源没有释放,从而形成线程垃圾。这些线程垃圾无法回收。

简单的说:在Java中通过给一个线程打上中断标记,告知这个中断你可以中断。之后,在该线程中通过try–catch方法捕捉线程出发的异常信号InterruptedException来进行中断。
其中给线程打上中断标记就是就是设置,线程的的中断状态为ture; 线程正常执行时为执行态,无法被中断。当线程调用一些中断方法时,线程会进入阻塞态,并放出InterruptedException。此时线程可以中断,中断响应后,重置中断状态为 false
(中断方法:Object.wait(), Object.wait(long), Object.wait(long, int), Thread.sleep(long), Thread.interrupt(), Thread.interrupted(), Serialized Form

public class MyRunnable implements Runnable {

	// 我们把要执行的任务代码写在 run() 方法中
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + ": 我是普通的用户线程");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException ex) {
			System.out.println(Thread.currentThread().getName() + ": 检测到中断信号");
			return; // 停止该线程
		}
	}

	public static void main(String[] args) {
		Thread thread = new Thread(new MyRunnable());
		thread.start();
		thread.interrupt();
	}
}

// 输出
main: 我照常运行
Thread-0: 我是普通的用户线程
Thread-0: 检测到中断信号

如果在检测到线程中断异常之后没有 通过 return;来终止该线程,线程就会继续往下运行。

在代码运行中,可以使用 Thread.currentThread().isInterrupted(); 来判断线程的中断状态来。

守护线程

用户线程:我们直接创建的线程为用户线程,当一个进程不包含任何存活的用户线程时,进程结束。
守护线程:守护线程是一个具有低优先级且运行在后台的线程,如:垃圾回收线程。当最后一个线程结束时,守护线程结束。

java中我们只需要调用 Thread.setDaemon(); 来将创建的线程设置为守护进线程。这个方法一定要在线程 start 之前使用。

	Thread t = new Thread(new MyRunnable());
	t.setDaemon();
	t.start();

线程池

为了最大化的压榨计算机的资源和运算能立,在运行项目的时候会大量的使用多线程模式进行操作。但是频繁的创建线程和销毁线程,会占用大量的cpu和内存,同时也会让gc承担巨大的压力。与之相比,运行线程所使用的资源显得微乎其微。因此因此频繁的创建和销毁线程的行为并不可取,也因此就产生了线程池。
线程池可以简单的分为四类:

		ExecutorService pool;
		pool = Executors.newCachedThreadPool();
		pool = Executors.newFixedThreadPool(3);
		pool = Executors.newSingleThreadExecutor();
		pool = Executors.newSingleThreadScheduledExecutor();
		//pool = Executors.newWorkStealingPool();

例如:

public static void main(String[] args) {
		// Thread thread = new Thread(new Test());
		// thread.start();

		// System.out.println(Thread.currentThread().getName() + ": 我照常运行");
		// thread.interrupt();

		ExecutorService pool = Executors.newFixedThreadPool(2);

		pool.execute(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
				try{
					Thread.sleep(3000);
				} catch(InterruptedException e){}
			}
		});
		pool.execute(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
				try{
					Thread.sleep(5000);
				} catch(InterruptedException e){}
			}
		});
		pool.execute(() -> {
			System.out.println(Thread.currentThread().getName());
		});
	}

// 输出
pool-1-thread-1
pool-1-thread-2
// 3秒后
pool-1-thread-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值