javaAPI_多线程基础_多线程基础4


多线程基础4


1.线程组概述和使用

(1).线程组概述
Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

(2).代码测试
//线程类代码
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
//测试类代码
public class ThreadGroupDemo {
public static void main(String[] args) {
// method1();

// 我们如何修改线程所在的组呢?
// 创建一个线程组
// 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
method2();

// t1.start();
// t2.start();
}

/*
* 重新创建线程组
*
*/
private static void method2() {
// ThreadGroup(String name)
ThreadGroup tg = new ThreadGroup("这是一个新的组");

MyRunnable my = new MyRunnable();
// Thread(ThreadGroup group, Runnable target, String name):把线程指定为某一个线程组的
Thread t1 = new Thread(tg, my, "林青霞");
Thread t2 = new Thread(tg, my, "刘意");

System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());

//通过组名称设置后台线程,表示该组的线程都是后台线程
tg.setDaemon(true);
}

/*
* 默认情况测试
* 获取当前的线程组以及使用线程组中的方法
*/
private static void method1() {
MyRunnable my = new MyRunnable();
Thread t1 = new Thread(my, "林青霞");
Thread t2 = new Thread(my, "刘意");
// 我不知道他们属于那个线程组,我想知道,怎么办
// 线程类里面的方法:public final ThreadGroup getThreadGroup()
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
// 线程组里面的方法:public final String getName()
String name1 = tg1.getName();
String name2 = tg2.getName();
System.out.println(name1);
System.out.println(name2);
// 通过结果我们知道了:线程默认情况下属于main线程组
// 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
System.out.println(Thread.currentThread().getThreadGroup().getName());
}
}


2.线程池概述以及使用

(1).概述
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是
当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

(2).线程池的特点
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用


(3).JDK5新增了一个Executors工厂类来产生线程池。具体方法如下:
public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()

这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。
它提供了如下方法:
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)

(4).线程池使用测试

A:如何实现线程的代码呢?
A:创建一个线程池对象,控制要创建几个线程对象。
public static ExecutorService newFixedThreadPool(int nThreads)
B:这种线程池的线程可以执行:
可以执行Runnable对象或者Callable对象代表的线程
做一个类实现Runnable接口。
C:调用如下方法即可
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
D:我就要结束,可以吗?
可以。

B:具体使用代码:
//线程类代码
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
//测试类代码
public static void main(String[] args) {
// 创建一个线程池对象,控制要创建几个线程对象。
// public static ExecutorService newFixedThreadPool(int nThreads)
ExecutorService pool = Executors.newFixedThreadPool(2);

// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());

//结束线程池
pool.shutdown();
}


3.匿名内部类实现多线程

(1).实际开发中最简单的方式开启另一个线程,那么就是使用匿名内部类的方式实现。
new Thread(){代码…}.start();
New Thread(new Runnable(){代码…}).start();


(2).代码实现
/*
* 匿名内部类的格式:
* new 类名或者接口名() {
* 重写方法;
* };
* 本质:是该类或者接口的子类对象。
*/
public class ThreadDemo {
public static void main(String[] args) {
// 继承Thread类来实现多线程
new Thread() {
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":"
+ x);
}
}
}.start();

// 实现Runnable接口来实现多线程
new Thread(new Runnable() {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":"
+ x);
}
}
}) {
}.start();

// 更有难度的
new Thread(new Runnable() {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println("hello" + ":" + x);
}
}
}) {
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println("world" + ":" + x);
}
}
}.start();
}
}

4.定时器

(1).概述
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和
TimerTask类来实现定义调度的功能

(2).相关方法
Timer类:定时
public Timer()
public void schedule(TimerTask task,long delay):延时指定时间以后执行任务
public void schedule(TimerTask task,long delay,long period):指定时间以后连续执行
public void cancel():终止任务

TimerTask类:任务(需要重写里面的方法)

(3).定时器基本使用测试[指定延时以后执行任务]
public class TimerDemo {
public static void main(String[] args) {
// 创建定时器对象
Timer t = new Timer();
// 3秒后执行爆炸任务
// t.schedule(new MyTask(), 3000);
//结束任务
t.schedule(new MyTask(t), 3000);
}
}

// 做一个任务
class MyTask extends TimerTask {

private Timer t;

public MyTask(){}

public MyTask(Timer t){
this.t = t;
}

@Override
public void run() {
System.out.println("beng,爆炸了");
t.cancel();
}
}

(4).多次执行代码[3秒后执行任务第一次,如果不成功,每隔2秒再继续]
public class TimerDemo2 {
public static void main(String[] args) {
// 创建定时器对象
Timer t = new Timer();
// 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
t.schedule(new MyTask2(), 3000, 2000);
}
}

// 做一个任务
class MyTask2 extends TimerTask {
@Override
public void run() {
System.out.println("beng,爆炸了");
}
}


(5).定时器使用案例:定时删除文件或者是文件夹
/*
* 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
*/

class DeleteFolder extends TimerTask {

@Override
public void run() {
File srcFolder = new File("demo");
deleteFolder(srcFolder);
}

// 递归删除目录
public void deleteFolder(File srcFolder) {
File[] fileArray = srcFolder.listFiles();
if (fileArray != null) {
for (File file : fileArray) {
if (file.isDirectory()) {
deleteFolder(file);
} else {
System.out.println(file.getName() + ":" + file.delete());
}
}
System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
}
}
}

public class TimerTest {
public static void main(String[] args) throws ParseException {
Timer t = new Timer();

String s = "2014-11-27 15:45:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);

t.schedule(new DeleteFolder(), d);
}
}


5.多线程相关面试题

(1):多线程有几种实现方案,分别是哪几种?
两种。

继承Thread类
实现Runnable接口

扩展一种:实现Callable接口。这个得和线程池结合。

(2):同步有几种方式,分别是什么?
两种。

同步代码块
同步方法

(3):启动一个线程是run()还是start()?它们的区别?
start();

run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法

(4):sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。
wait():可以不指定时间,也可以指定时间;释放锁。

(5):为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。

(6):线程的生命周期图
新建 -- 就绪 -- 运行 -- 死亡
新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
建议:画图解释。

猜你喜欢

转载自www.cnblogs.com/nwxayyf/p/10290695.html