1.线程的创建和运行
package cn.fans.chapter1.one;
/**
*
* @author fcs
* @date 2015-4-11
* 描述:打印乘法表
* 说明:
*/
public class Calculator implements Runnable {
private int number;
public Calculator(int number) {
this.number = number;
}
@Override
public void run() {
for(int i = 0 ;i< 10;i++){
System.out.printf("%s: %d * %d = %d\n",Thread.currentThread().getName(),number,i,i*number);
}
}
}
package cn.fans.chapter1.one;
public class Main {
public static void main(String [] argc){
for(int i =0 ;i<10;i++){
Calculator calculator = new Calculator(i);
Thread thread = new Thread(calculator);
thread.start();
}
}
}
2.线程信息的获取和设置
package cn.fans.chapter1.two;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程信息的获取和设置
* 说明:第二种方式实现多线程
*/
public class Calculator extends Thread {
private int number;
public Calculator(int number) {
super();
this.number = number;
}
@Override
public void run(){
for(int i =0;i<10;i++){
System.out.printf("%s: %d * %d = %d\n",Thread.currentThread().getName(),number,i,number*i);
}
}
}
package cn.fans.chapter1.two;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.lang.Thread.State;
public class Main {
public static void main(String[] args) {
Thread [] thread = new Thread[10];
//保存线程运行的状态
Thread.State status [] = new Thread.State[10];
for(int i =0 ;i< 10;i++){
thread[i] = new Thread(new Calculator(i));
if((i % 2 ==0)){
thread[i].setPriority(Thread.MAX_PRIORITY);
}
else {
thread[i].setPriority(Thread.MIN_PRIORITY);
}
thread[i].setName(“Thread”+i);
}
try{
FileWriter file = new FileWriter("log.txt");
PrintWriter pw =new PrintWriter(file); //这里的pw没有写入文件,不知道为啥、
//记录线程的状态
for(int i =0 ;i< 10;i++){
pw.println("Main: status of Thread "+ i+ ":"+thread[i].getState());
status[i] = thread[i].getState();
}
//开始线程
for(int i =0 ; i < 10;i ++){
thread[i].start();
}
boolean finish = false;
while(!finish){
for(int i = 0 ;i < 10;i++){
if(thread[i].getState() != status[i]){
writeThreadInfo(pw,thread[i],status[i]);
status[i] = thread[i].getState();
}
}
finish = true;
for(int i =0;i<10;i++){
finish = finish &&(thread[i].getState() == State.TERMINATED);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
//写下线程的相关信息
private static void writeThreadInfo(PrintWriter pw,Thread thread,State state){
pw.printf("Main: Id %d - %s\n",thread.getId(), thread.getName());
pw.printf("Main : Prority: %d\n",thread.getPriority());
pw.printf("Main : Old state : %s\n",state);
pw.printf("Main : new State : %s\n", thread.getState());
pw.printf("Main ************************************");
}
}
3.线程的中断
package cn.fans.chapter1.three;
/**
* 线程的中断设置
* @author fcs
* @date 2015-4-10
* 描述:在打印素数的过程中设置中断
* 说明:
*/
public class PrimeGenerator extends Thread {
@Override
public void run(){
long number = 1L;
while(true){
if(isPrime(number)){
System.out.printf(“number %d is Prime\n”,number);
}
if(isInterrupted()){
System.out.println(“The Prime Generatro has been Interrupted “);
return;
}
number ++;
}
}
private boolean isPrime(long number){
if(number <= 2){
return false;
}
for(long i = 2;i< number;i++){
if((number % i) == 0){
return false;
}
}
return true;
}
}
package cn.fans.chapter1.three;
public class Main {
public static void main(String[] args) {
Thread task = new PrimeGenerator();
task.start();
try{
Thread.sleep(5000); //休眠5秒后进行中断操作
}catch(InterruptedException e){
e.printStackTrace();
}
task.interrupt(); //终止线程
}
}
4.线程中断的控制
**package cn.fans.chapter1.four;
import java.io.File;
import javax.naming.directory.DirContext;
/**
* 线程中断的控制
* @author fcs
* @date 2015-4-10
* 描述:文件搜索,根据文件名搜索文件,搜索到后则进行中断
* 说明:
*/
public class FileSearch implements Runnable {
private String initPath;
private String fileName;
public FileSearch(String initPath, String fileName) {
super();
this.initPath = initPath;
this.fileName = fileName;
}
public String getInitPath() {
return initPath;
}
public void setInitPath(String initPath) {
this.initPath = initPath;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* 这个方法检查fileName属性是不是一个目录,如果是就调用processDirectory 方法。procesDirectory方法会抛出
* InterruptedException异常,因此必须捕获并处理这个异常
*/
@Override
public void run() {
File file = new File(initPath);
if(file.isDirectory()){
try{
directoryProcess(file);
}catch (InterruptedException e) {
System.out.printf("%s : The seach has been interrupted",Thread.currentThread().getName());
}
}
}
/**
*
* 作者:fcs
* 描述:获得一个文件夹下的所有文件和子文件夹,并进行处理
* 对于每个记录这个方法采用递归调用。并用响应的目录名作为传入参数。
* 对于每个文件这个方法将调用fileProcess()方法,处理完所有的文件和文件夹后这个方法
* 将检查线程是否被中断了,如果是则抛出InterruptedException异常。
* 说明:
* 返回:
* 参数:
* 时间:2015-4-10
*/
private void directoryProcess(File file)throws InterruptedException{
File list [] = file.listFiles();
if(list != null ){
for(int i =0;i< list.length;i++){
if(list[i].isDirectory()){
directoryProcess(list[i]);
}else{
fileProcess(list[i]);
}
}
if(Thread.interrupted()){
throw new InterruptedException();
}
}
}
/**
*
* 作者:fcs
* 描述:比较当前的文件名和要查找的文件名。如果文件名匹配就将信息打印到控制台,
* 做完比较后线程将检查是不是被中断了,如果是抛出InterruptedException
* 说明:
* 返回:
* 参数:
* 时间:2015-4-10
*/
private void fileProcess(File file)throws InterruptedException{
if(file.getName().equals(fileName)){
System.out.printf("%S : %S\n",Thread.currentThread().getName(),file.getAbsolutePath());
}
if(Thread.interrupted()){
throw new InterruptedException();
}
}
}
package cn.fans.chapter1.four;
import java.util.concurrent.TimeUnit;
/**
* 本例使用java异常来控制中断,使用递归的时候,不管递归调用了多少次,只要线程检测到自己已经被中断了,就会立刻抛出InterruptedException异常,
* 然后继续执行run方法
* @author fcs
* @date 2015-4-10
* 描述:
* 说明:
*/
public class Main {
public static void main(String[] args) {
FileSearch fileSearch = new FileSearch("C:\\Documents and Settings\\teacher\\workspace\\javaThread", "FileSearch.java");
Thread thread = new Thread(fileSearch);
thread.start();
try{
TimeUnit.SECONDS.sleep(10); //等待十秒
}catch(InterruptedException e){
e.printStackTrace();
}
thread.interrupt();
}
}
5.线程的休眠和恢复
package cn.fans.chapter1.five;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程的休眠和恢复
* 说明:在线程被挂起的时钟周期内,线程什么都不做,不占用计算机资源
* 当该线程的执行的CPU执行周期来临的时候,JVM会选中它继续执行。
* 可以使用线程的sleep()方法来达到这个目标。
* 这里使用sleep方法,每隔一秒就输出实际时间、
*/
public class FileClock implements Runnable {
@Override
public void run() {
for(int i =0;i< 10;i++){
System.out.printf(“%s\n”,new Date());
try{
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e) {
e.printStackTrace();
System.out.println(“The fileClock has been interrupted”);
}
}
}
}
package cn.fans.chapter1.five;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:当线程被中断时,释放或者关闭线程正在使用的资源。
* 如果休眠中线程被中断,该方法就会立即抛出InterruptedException异常,而不需要等待线程休眠时间结束
* 说明:
*/
public class FileMain {
public static void main(String[] args) {
FileClock fileClock = new FileClock();
Thread thread = new Thread(fileClock);
thread.start();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
6.等待线程的终止
package cn.fans.chapter1.six;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:等待线程的终止
* 举例:先初始化一些必须的资源,可以使用线程完成一些初始化任务。
* 等待线程结束,再执行程序的其他任务。
* 说明:
*/
public class DataSourceLoader implements Runnable{
@Override
public void run() {
System.out.printf("Beginning data source loading: %s\n",new Date());
try{
TimeUnit.SECONDS.sleep(4); //模拟执行四秒
}catch (Exception e) {
e.printStackTrace();
}
System.out.printf("Data source loadign has finished: %s\n",new Date());
}
}
package cn.fans.chapter1.six;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:同DataSourceLoader
* 说明:
*/
public class NetWorkConnectionLoader implements Runnable{
@Override
public void run() {
System.out.printf("Beginning net work loadging :%s /n",new Date());
try{
TimeUnit.SECONDS.sleep(10);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("network loading has finished %s \n",new Date());
}
}
package cn.fans.chapter1.six;
import java.util.Date;
public class Main {
public static void main(String[] args) {
DataSourceLoader dataSourceLoader = new DataSourceLoader();
NetWorkConnectionLoader netWorkConnectionLoader = new NetWorkConnectionLoader();
Thread thread1 = new Thread(dataSourceLoader);
Thread thread2 = new Thread(netWorkConnectionLoader);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Main: Configration has been loaded: %s \n",new Date());
}
}
7.守护线程的创建和运行
package cn.fans.chapter1.seven;
import java.util.Date;
public class Event {
private Date date;
private String event;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}
package cn.fans.chapter1.seven;
import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:守护线程的创建和运行
* 说明:
*/
public class WriteTask implements Runnable{
private Deque deque;
public WriteTask(Deque<Event> deque) {
this.deque = deque;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Event event = new Event();
event.setDate(new Date());
event.setEvent(String.format("The thread %s has generated an event", Thread.currentThread().getId()));
deque.addFirst(event);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package cn.fans.chapter1.seven;
import java.util.Date;
import java.util.Deque;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:设置该线程为守护线程
* 说明:
*/
public class CleaerTask extends Thread {
private int count; //计数清除的事件数量
private Deque deque;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public CleaerTask(Deque<Event> deque,int count) {
this.deque = deque;
setDaemon(true);
this.count = count;
}
@Override
public void run() {
while(true){
Date date = new Date();
clean(date);
}
}
/**
*
* 作者:fcs
* 描述:该方法读取队列的最后一个事件对象,如果这个时间是10秒钟前创建的,
* 就将它删除并检查下一个,如果有事件被删除,clean将打印出这个事件的信息,
* 也打出队列的长度。
* 说明:
* 返回:
* 参数:
* 时间:2015-4-10
*/
private void clean(Date date){
long difference;
boolean delete;
if(deque.size() == 0){
return ;
}
delete = false;
do{
Event e = deque.getLast();
difference = date.getTime() - e.getDate().getTime();
if(difference > 10000){
System.out.printf("Cleaner: %s \n",e.getEvent());
deque.removeLast();
count ++;
delete = true;
}
}while(difference > 10000);
if(delete){
System.out.printf("Cleaer : Size of the queue: %d \n",deque.size());
System.out.println("coutn = "+count);
}
}
}
package cn.fans.chapter1.seven;
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
Deque deque = new ArrayDeque();
WriteTask writer = new WriteTask(deque);
for(int i =0;i< 3;i++){
Thread thread = new Thread(writer);
thread.start();
}
CleaerTask cleaerTask = new CleaerTask(deque,0);
cleaerTask.start();
}
}
8.线程中不可控异常的处理
package cn.fans.chapter1.eight;
import java.lang.Thread.UncaughtExceptionHandler;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程中不可控异常的处理
* 说明:
*/
public class ExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
//运行到这里就结束了,只是输出第一句话
System.out.printf("An Exception has been captured");
System.out.printf("Thread %\n",t.getId());
System.out.printf("Exception: %s\n",e.getClass().getName(),e.getMessage());
System.out.printf("Stack Trace \n");
e.printStackTrace(System.out);
System.out.printf("Thread status: %s \n",t.getState());
}
}
package cn.fans.chapter1.eight;
public class Task implements Runnable{
@Override
public void run() {
int i = Integer.parseInt(“TT”);
}
}
package cn.fans.chapter1.eight;
public class Main {
public static void main(String[] args) {
Task task = new Task();
Thread thread = new Thread(task);
//设置线程的运行时异常处理器
thread.setUncaughtExceptionHandler(new ExceptionHandler());
thread.start();
}
}
9.线程局部变量的使用
package cn.fans.chapter1.nine;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程局部变量的使用
* 说明:,对于继承了Thread类或者实现了Runnable接口的对象来说这些所有的线程都将共享相同的变量
* 如果一个实现了Runnable接口的对象在一个线程中改变了一个树形,所有的线程都会被这个改变影响
*
* 输出结果与书上不一致,共享变量会被修改,不安全
*/
public class UnsafeTask implements Runnable{
private Date startDate;
@Override
public void run() {
startDate = new Date();
System.out.printf(“Starting Thread %s: %s\n”,Thread.currentThread().getId(),startDate);
try {
TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf(“Thread Finished %s : %s\n”,Thread.currentThread().getId(),startDate);
}
}
package cn.fans.chapter1.nine;
import java.util.concurrent.TimeUnit;
public class Core {
public static void main(String[] args) {
UnsafeTask unsafeTask = new UnsafeTask();
//启动十个线程每个线程启动时间为两秒
for(int i =0 ;i< 10;i++){
Thread thread = new Thread(unsafeTask);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package cn.fans.chapter1.nine;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:使用线程局部变量来解决线程共享变量的问题
* 说明:
*/
public class SafeTasks implements Runnable{
private static ThreadLocal startDate = new ThreadLocal(){
protected Date initialValue() {
return new Date();
};
};
@Override
public void run() {
System.out.printf("Starting Thread :%s : %s\n",Thread.currentThread().getId(),startDate.get());
try {
TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished : %s : %s\n",Thread.currentThread().getId(),startDate.get());
}
}
package cn.fans.chapter1.nine;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程局部变量的安全方式
* 说明:
*/
public class Cores {
public static void main(String[] args) {
SafeTasks safeTasks = new SafeTasks();
for(int i =0 ;i<10;i++){
Thread thread = new Thread(safeTasks);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
10.线程的分组
package cn.fans.chapter1.ten;
public class Result {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package cn.fans.chapter1.ten;
import java.util.Date;
import java.util.Random;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程的分组
* 说明:把一个组的线程当成单一的单元,对组内线程对象进行访问并操作他们
* java提供ThreadGroup 类表示一组线程,线程组可以包含线程对象,也可以包含其他的线程
* 组对象,是一个树形结构。
*/
public class SearchTask implements Runnable {
private Result result;
public SearchTask(Result result) {
this.result = result;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.printf("Thread %s: Start\n",name);
try {
doTask();
result.setName(name);
} catch (InterruptedException e) {
System.out.printf("Thread %s :interrupted\n",name);
return ;
}
System.out.printf("Thread %s End\n",name);
}
private void doTask() throws InterruptedException{
Random random = new Random((new Date()).getTime());
int value = (int)(random.nextDouble()*100);
System.out.printf("Thread %s : %d\n",Thread.currentThread().getName(),value);
}
}
package cn.fans.chapter1.ten;
import java.util.concurrent.TimeUnit;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:创建线程组对象
* 说明:这里运行结果不同,需要研究
*/
public class Main {
public static void main(String[] args) {
ThreadGroup threadGroup = new ThreadGroup(“Searcher”);
Result result = new Result();
SearchTask searchTask = new SearchTask(result);
//线程是逐个输出的,所以线程组输出信息的时候,线程组的大小是0???
for(int i =0 ;i< 5;i++){
Thread thread = new Thread(threadGroup,searchTask);
thread.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//获取线程组包含线程的数量
System.out.printf("Number of Threads %d\n",threadGroup.activeCount());
System.out.printf("Information about the thread group \n");
threadGroup.list(); //这里并没有打印??
Thread [] threads = new Thread[threadGroup.activeCount()];
threadGroup.enumerate(threads);
for(int i=0;i<threadGroup.activeCount();i++){
System.out.printf("Thread %s : %s\n",threads[i].getName(),threads[i].getState());
}
waitFinish(threadGroup);
Thread.interrupted(); //该方法将终端这个组的其余线程
}
private static void waitFinish(ThreadGroup threadGroup){
while(threadGroup.activeCount() > 9){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
11.线程组中不可控异常的处理
package cn.fans.chapter1.eleven;
import java.util.Random;
public class Task implements Runnable{
@Override
public void run() {
int result;
Random random = new Random(Thread.currentThread().getId());
while(true){
result = 1000 / ((int) random.nextDouble()*1000);
System.out.printf(“%s : %d\n”,Thread.currentThread().getId(),result);
if(Thread.currentThread().isInterrupted()){
System.out.printf(“%d: Interrupted\n”,Thread.currentThread().getId());
return ;
}
}
}
}
package cn.fans.chapter1.eleven;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程组中不可控异常的处理
* 说明:
*/
public class MyThreadGroup extends ThreadGroup{
public MyThreadGroup(String name) {
super(name);
}
/**
* 重写uncaughtException(),当线程组中的任何线程对象抛出异常的时候,这个方法会被调用
* 打印异常信息和抛出异常的线程代码到控制台,并且中断线程组的其他线程
*/
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.printf("The thread %s has thrown an Exception\n",t.getId());
e.printStackTrace();
System.out.println("Terminating the rest of the Threads\n");
interrupt();
}
}
package cn.fans.chapter1.eleven;
public class Main {
public static void main(String[] args) {
MyThreadGroup myThreadGroup = new MyThreadGroup(“MyThreadGroup”);
Task task = new Task();
for(int i =0 ;i< 2;i++){
Thread t = new Thread(myThreadGroup,task);
t.start();
}
}
}
13.使用工厂类创建线程
package cn.fans.chapter1.twelve;
import java.util.concurrent.TimeUnit;
/**
* 线程对象,在线程工厂中批量生产
*/
public class Task implements Runnable{
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package cn.fans.chapter1.twelve;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ThreadFactory;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:使用工厂类创建线程
* 说明:java提供了ThreadFactory接口,这个接口实现了线程对象工厂
*/
public class MyThreadFactory implements ThreadFactory{
private int counter;
private String name;
private List<String> states;
public MyThreadFactory(String name) {
counter = 0;
states = new ArrayList<String>();
this.name = name;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r,name+"-Thread_"+counter);
states.add(String.format("Created thread %d with name %s on %s\n", t.getId(),t.getName(),new Date()));
return t;
}
/**
*
* 作者:fcs
* 描述:返回一个字符串对象
* 说明:用来表示所有线程对象的统计数据
* 返回:
* 参数:
* 时间:2015-4-10
*/
public String getStats(){
StringBuffer stringBuffer = new StringBuffer();
Iterator<String> it = states.iterator();
while(it.hasNext()){
stringBuffer.append(it.next());
stringBuffer.append("\n");
}
return stringBuffer.toString();
}
}
package cn.fans.chapter1.twelve;
/**
*
* @author fcs
* @date 2015-4-10
* 描述:线程工厂的演示
* 说明:
*/
public class Main {
public static void main(String[] args) {
MyThreadFactory threadFactory = new MyThreadFactory(“MyThreadFactory”);
Task task = new Task();
Thread thread;
System.out.println(“String the threads ..”);
for(int i = 0;i< 10;i++){
thread = threadFactory.newThread(task);
thread.start();
}
System.out.printf(“Factory stats:\n”);
System.out.printf(“%s\n”,threadFactory.getStats());
}
}
第一章 学习笔记
第一章笔记
1.线程的创建有两种方式
1.继承Thread类,并且覆盖run方法
2.实现Runnable接口,使用带参数的Thread构造函数创建thread将实现该接口的对象传入构造函数中
说明:在main方法中运行的main线程是父线程,当程序执行的时候,JVM将启动这个执行线程来执行程序的main()
调用run()方法不会创建一个新的执行线程,程序不会执行,只有调用start()方法才会创建一个新的执行线程。
2.线程信息的获取和设置(thread类有的一些属性,用来标示线程的状态,线程名称,线程的优先级等)
1.ID:线程的状态
2.Name:线程的名称
3.Priority:线程对象的优先级 1—-10,依次增高
4.Status:线程的状态:线程有六种状态: new runnable blocked waiting time waiting terminated
本实例中优先级高的线程会提前输出结束,在创建FileWriter类和PrintWriter类后并没有把线程的演变信息写入到log.txt中,todo why?
5.Thread类的属性存储了线程的所有信息,JVM使用线程的priority属性来决定某一时刻由哪个线程来使用CPU,并且根据线程的情景为它们设置实际的状态
6.线程的状态和ID是不能修改的,但是可以设置优先级
3.线程的中断
1.Thread类的静态方法interrupted()用来检查当前执行的线程是否被中断
2.isInterrupted()方法不能改变interrupted属性的值,而1的方法可以改变
3.推荐使用Isinterrupted()方法
4.java中的中断机制可以用来结束一个线程,这个机制要求线程检查它是否被中断了,然后决定是不是响应这个中断的请求,线程允许忽略中断请求并且继续执行。
4.线程中断的控制
1.可以使用InterruptedException在检查线程被中断的时候抛出该异常,进而控制线程的中断。
2.sleep()方法也会抛出这个异常
3.抛出该异常后,程序会继续执行run方法的内容。
5.线程的休眠和恢复
1.通过sleep(time)控制线程休眠的时间,当线程休眠的时间过完后,JVM会执行该线程
2.可以通过TimeUnit枚举类元素来进行调用,这个方法也是使用Thread sleep方法使当前线程休眠,但是接受的参数时间单位是秒,最后会被转换成毫秒
3.java API 提供了另一个方法来使线程对象释放CPU,就是yield(),该方法通知JVM这个线程对象可以释放CPU了,但是JVM并不一定会释放,因此该方法建议在调试的时候使用
6.等待线程的终止
1.说明在一定情况下,我们必须等待线程终止,比如在初始化程序资源的时候。可以使用join()方法,调用它的线程将被挂起,直到整个线程对象完成它的任务。
2.join()方法会抛出InterruptedException异常,因此我们必须捕获并处理这个异常
3.join()方法的两个重载方法join(long milliseconds)和join(long milliseconds,long nanos):
使用一个参数的join方法,说明调用者要等到milliseconds的时间来让被调用线程执行,当被调用线程执行完成,调用者才能继续执行。
或者在milliseconds的时间内被调用者没有执行完毕,那么调用者会继续执行。
7.守护线程的创建和运行
1.java中有一种特殊的线程叫守护线程。这种线程的优先级很低。当同一个应用程序只有守护线程的时候,守护线程执行结束后JVM就会结束这个程序
2.说明这个程序在跑的时候并没有同书上说的一样,会在10秒内产生30个事件,实际上线程的创建和初始化都是需要一定的时间的,在cleaner线程中
线程只是等待10秒钟后清除存在队列中的多余10秒的事件,在创建的三个写线程中并没有执行300次(不知道为什么??),最后队列里面总会保存和
10秒内创建事件数量差不多的数量,也就是说剩下的那些都是新的事件,清除线程并没有来得及清除。
8.线程中不可控异常的处理
1.java中的两种异常: 1.非运行时异常,必须在方法中声明throws语句,或者再方法里捕获异常。
2.运行时异常,不必在方法中声明指定,也不需要在方法中捕获
3.因为run方法不支持throw语句,所以当线程对象的run方法抛出非运行时异常,我们必须捕获她,当运行时异常从run方法中抛出的时候,默认在控制台中打印出堆栈记录并且推出程序
4.当线程抛出一个未捕获的异常时,JVM将寻找下面三种可能的处理器处理异常。
1.首先查找线程对象的未捕获异常处理器。
2.如果找不到1则会查找所在线程组中的未捕获异常处理器
3.如果找不到2,JVM会使用默认的未捕获异常处理器。
4.如果这些处理器都不存在,JVM则会将堆栈中异常信息打印到控制台,并推出这个程序。
9.线程局部变量的使用
1.如果创建的对象是实现了Runnable接口的类的实例,用它做为传入参数创建多个线程,并启动这些线程,那么所有的线程将共享相同的属性,
也就是说你在一个线程中改变了这些属性,所有线程都会被这个改变所影响。
2.在某种情况下,这个对象的属性不需要被所有线程共享,java并发API提供了一个干净的机制,线程局部变量---ThreadLocal
3.在不安全的线程演示中,出现了和书上一样的情况,就是多个线程会有相同的开始时间。实际上不应该出现,刚开始我理解错了。
4.而使用线程局部变量后,所有的线程的开始时间都不是相同的,而且是根据休眠时间逐渐递增的。
10.线程的分组:
1.使用ThreadGroup对象类创建线程组对象。可以包含线程组对象也可以包含线程对象,是个树形结构。
2.这个运行同样没有出现书中截图的结果,在这里记录一下,代码应该没有写错,希望阅读者可以一起探讨为什么。
11.线程组中不可控异常的处理
1.在并发编程网中一位翻译将非运行时异常翻译成检查异常,将运行时异常翻译成未检查异常。
2.只要记住非运行时异常需要进行处理,而运行时异常不需要被捕获或者声明抛出。
3.处理异常的方式与第八个实例相同
12.使用工厂类创建线程
1.这里使用了工厂方法模式
2.java提供了ThreadFactory接口,这个接口实现了线程工厂
3.自定义线程工厂可以实现一些个性化需求
4.该接口只有一个方法newThread(),以Runnable对象作为传入参数。实现该接口时需要实现该方法。
好处:
1.创建一个个性化线程。
2.保存新创建的线程的统计数据
3.限制创建线程的数量
4.对生成的线程进行验证
5.注意确保生成的线程都是由同一个线程工厂生产的。
13.本章线程常用的类
1.Thread Runnable TimeUnit ThreadLocal ThreadGroup ThreadFactory InterruptedException UncaughtExceptionHandler
2.本章常用的方法
1.start(): 线程执行方法,该方法只能被调用一次,否则抛出异常,在执行该方法时,Thread内部会将该线程对象放入线程组中,并减少没有启动线程的数量。
2.run():该方法在创建线程对象的时候使用Thread构造方法使用私有的init方法传入Runnable对象,从而在调用start()的时候调用native修饰的start0()并执行run()
3.join(): 调用执行该方法会将自己挂起,等待当前线程执行结束,该方法会抛出InterruptedException异常,
该方法内部调用join(long milliseconds)方法传入参数为0,有三个join()的方法,该方法会在某些方便比较常用。
4.sleep():该方法同样是比较常用的而且有很两个重载方法,一般会模拟线程执行任务的时间,或者什么也不做。等待一定的时间,时钟周期到达的时候JVM会自动调用该线程。
该方法同样会抛出InterruptedException异常。带一个参数的是本地方法。两个参数的方法内部会调用该方法。
5.interrupted(): 判断当前线程是否被终止。
6.interrupt():该方法用来中断当前线程,使用interrupt0()本地方法设置中断状态码。
7.TimeUnit中的sleep():TimeUnit提供了可读性更好的线程暂停操作,通常用来替换Thread.sleep(),因为后者在睡眠时间上要进行单位转换,而TimeUnit的sleep方法则不需要。
thread的sleep是一个重载方法,可以接收长整型毫秒和长整型的纳秒参数,但是不能准确的知道睡眠多少时间,因此使用TimeUnit可以让代码更有可读性。
8.setDaemon()设置守护线程,该方法必须在start()方法前执行
面试题1:
3、为什么需要run()和start()方法,我们可以只用run()方法来完成任务吗?
我们需要run()&start()这两个方法是因为JVM创建一个单独的线程不同于普通方法的调用,
所以这项工作由线程的start方法来完成,start由本地方法实现,需要显示地被调用,
使用这俩个方法的另外一个好处是任何一个对象都可以作为线程运行,只要实现了Runnable接口,
这就避免因继承了Thread类而造成的Java的多继承问题。