(转载请标明出处)
多线程概念:
![]()
![]()
![]()
![]()
线程的创建和启动:
![]()
public class FirstThread extends Thread {
private int i;
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
new FirstThread().start();
new FirstThread().start();
}
}
}
}
![]()
![]()
public class SecondThread implements Runnable {
private int i;
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20){
SecondThread st = new SecondThread();
//通过new Thread(target , name)方法创建新线程
new Thread(st,"新线程1").start();
new Thread(st,"新线程2").start();
}
}
}
}
![]()
![]()
![]()
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Integer> f1 = es.submit(newMyCallable(10));
Future<Integer> f2 = es.submit(new MyCallable(20));
System.out.println(f1.get()+" "+ f2.get());
es.shutdown();
![]()
FutureTask<Integer> ft = new FutureTask<Integer>(new MyCallable(10));
FutureTask<Integer> ft2 = new FutureTask<Integer>(new MyCallable(20));
new Thread(ft,"我是线程1").start();
new Thread(ft2,"我是线程2").start();
System.out.println(ft.get());
![]()
public class ThirdThread {
public static void main(String[] args){
//创建Callable对象
ThirdThread rt = new ThirdThread();
//使用Lambda表达式创建Callable<Integer>对象
//使用FutureTask来包装Callable对象
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() ->{
int i = 0;
for(; i < 100; i++){
System.out.println(Thread.currentThread().getName() + "i值:"+ i);
}
//call()方法可以有返回值
return i;
});
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"i值:"+ i);
if(i==20){
//实质还是以Callable对象来创建并启动线程的
new Thread(task,"有返回值的线程").start();
}
}
try {
System.out.println("子线程的返回值"+ task.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
![]()
线程的生命周期:
![]()
![]()
![]()
![]()
![]()
![]()
控制线程:
![]()
public class JoinThread extends Thread{
public JoinThread(String name){
super(name);
}
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName() + " " +i);
}
}
public static void main(String[] args) throws InterruptedException{
new JoinThread("新线程").start();
for (int i = 0; i < 100; i++) {
if(i == 20){
//当i==20时 jt开始启动,main线程阻塞
JoinThread jt = new JoinThread("被Join的线程");
jt.start();
//main线程调用了jt线程的join()方法,main线程必须等到jt执行结束
//才会向下执行
jt.join();
}
System.out.println(Thread.currentThread().getName() + " " +i);
}
}
}
![]()
public class DaemonThread extends Thread{
//后台线程的线程执行体与普通线程没有任何区别
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println(getName() + " " +i);
}
}
public static void main(String[] args) throws InterruptedException{
DaemonThread dt = new DaemonThread();
dt.setDaemon(true);
dt.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
//----------程序执行到此,前台线程main线程结束------------
//后台线程也随之结束
}
}
![]()
![]()
![]()
public class PriorityTest extends Thread{
public PriorityTest(String name){
super(name);
}
public void run(){
for (int i = 0; i < 50; i++) {
System.out.println(getName() + "优先级:" +getPriority()+" i:"+i);
}
}
public static void main(String[] args) throws InterruptedException{
//改变主线程的优先级
Thread.currentThread().setPriority(6);
for (int i = 0; i < 30; i++) {
if(i == 10){
PriorityTest pt1 = new PriorityTest("低级");
pt1.start();
System.out.println("创建时的优先级:"+pt1.getPriority()+" i:"+i);
pt1.setPriority(MIN_PRIORITY);
}
if(i == 20){
PriorityTest pt2 = new PriorityTest("高级");
pt2.start();
System.out.println("创建时的优先级"+pt2.getPriority()+" i:"+i);
pt2.setPriority(MAX_PRIORITY);
}
}
}
}
![]()
线程同步:
![]()
![]()
![]()
![]()
public class DrawThread extends Thread{
//模拟用户账户
private Account account;
//当前取钱线程所希望的取的钱数
private double drawAmount;
public DrawThread(String name,Account account,double drawAmount){
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
//当多个线程修改同一个共享数据时,将涉及数据安全问题
public void run(){
account.draw(drawAmount);
}
public static void main(String[] args) throws InterruptedException{
Account acct = new Account("123456",1000);
new DrawThread("甲",acct,800).start();
new DrawThread("乙",acct,800).start();
}
}
class Account{
private String accountNo;
private double balance;
public Account(){}
public Account(String accountNo, double balance){
this.accountNo = accountNo;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
//因为账户余额不允许随便修改,所以只为balance提供getter方法
public double getBalance() {
return balance;
}
//提供一个线程安全的draw()方法来完成取钱操作
public synchronized void draw(double drawAmount){
if(balance >= drawAmount){
System.out.println(Thread.currentThread().getName()+"取钱成功"+drawAmount);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
balance -= drawAmount;
System.out.println("\t余额:"+balance);
}else{
System.out.println(Thread.currentThread()+"取钱失败");
}
}
}
![]()
同步锁(Lock):
![]()
public class test02 {
private final ReentrantLock lock = new ReentrantLock();
public void m(){
//加锁
lock.lock();
try{
//需要保证线程安全的代码
//...
}
//使用finally块来保证释放锁
finally{
lock.unlock();
}
}
}
![]()
![]()
public class DeadLock implements Runnable {
A a = new A();
B b = new B();
public void init(){
Thread.currentThread().setName("主线程");
a.foo(b);
System.out.println("进入主线程");
}
public void run(){
Thread.currentThread().setName("副线程");
b.bar(a);
System.out.println("进入副线程之后");
}
public static void main(String[] args) {
DeadLock dl = new DeadLock();
new Thread(dl).start();
dl.init();
}
}
class A{
public synchronized void foo(B b){
System.out.println("当前线程名:"+Thread.currentThread().getName()+"进入A实例的foo()方法");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程名:"+Thread.currentThread().getName()+"企图调用B实例的last()方法");
b.last();
}
public synchronized void last(){
System.out.println("进入A类的last()方法内部");
}
}
class B{
public synchronized void bar(A a){
System.out.println("当前线程名:"+Thread.currentThread().getName()+"进入B实例的bar()方法");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程名:"+Thread.currentThread().getName()+"企图调用A实例的last()方法");
a.last();
}
public synchronized void last(){
System.out.println("进入了B类的last()方法内部");
}
}
![]()
public class DeadLockDemo {
public static void main(String[] args) {
new Thread( new DeadLock(false)).start();
new Thread(new DeadLock(true)).start();
}
}
class DeadLock implements Runnable{
private static final Object objA = new Object();
private static final Object objB = new Object();
private boolean flag;
public DeadLock(boolean flag){
this.flag = flag;
}
@Override
public void run() {
while(true){
if(flag){
synchronized(objA){
System.out.println("if objA");
synchronized(objB){
System.out.println("if objB");
}
}
}else{
synchronized(objB){
System.out.println("else objB");
synchronized(objA){
System.out.println("else objA");
}
}
}
}
}
}
线程通信:
![]()
![]()
public class DrawTest {
public static void main(String[] args) {
//创建一个账户
Account acct = new Account("123",0);
new DrawThread("取钱者",acct,800).start();
new DepositThread("存钱者1", acct, 800).start();
new DepositThread("存钱者2", acct, 800).start();
new DepositThread("存钱者3", acct, 800).start();
}
}
class Account{
private String accountNo;
private double balance;
//标识账户中是否已经有存款的旗标
private boolean flag = false;
public Account(){}
public Account(String accountNo, double balance){
this.accountNo = accountNo;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
//因为账户余额不允许随便修改,所以只为balance提供getter方法
public double getBalance() {
return balance;
}
//提供一个线程安全的draw()方法来完成取钱操作
public synchronized void draw(double drawAmount){
try {
if(!flag){
wait();
}else{
//执行取钱操作
System.out.println(Thread.currentThread().getName()+"取钱"+drawAmount);
balance -= drawAmount;
System.out.println("账户余额为:"+balance);
flag = false;
//唤醒其他线程
notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void deposit(double depositAmount){
try {
//flag为true 表示账户已有人存钱进去,存钱方法阻塞
//当while判断后,wait()方法释放锁,唤醒其他线程去存钱,当存取次数相同时,此程序不会阻塞
// while(flag){
// wait();
// }
if(flag){
wait();
}else{
//执行存款操作
System.out.println(Thread.currentThread().getName()+"存款:"+ depositAmount);
balance += depositAmount;
System.out.println("账户余额:"+balance);
flag = true;
notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class DrawThread extends Thread{
//模拟用户取钱
private Account account;
//当前取钱线程所希望取的钱数
private double drawAmount;
public DrawThread(String name,Account account,double drawAmount){
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
public void run(){
for (int i = 0; i < 300; i++) {
System.out.println("取钱次数"+i);
account.draw(drawAmount);
}
}
}
class DepositThread extends Thread{
//模拟用户账户
private Account account;
//当前存钱线程所希望存的钱数
private double depositAmount;
public DepositThread(String name , Account account , double depositAmount){
super(name);
this.account = account;
this.depositAmount = depositAmount;
}
public void run(){
for (int i = 0; i < 100; i++) {
account.deposit(depositAmount);
}
}
}
![]()
![]()
class Account{
//显示定义Lock对象
private final Lock lock = new ReentrantLock();
//获得指定Lock对象对应的Condition
private final Condition cond = lock.newCondition();
private String accountNo;
private double balance;
//标识账户中是否已经有存款的旗标
private boolean flag = false;
public Account(){}
public Account(String accountNo, double balance){
this.accountNo = accountNo;
this.balance = balance;
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
//因为账户余额不允许随便修改,所以只为balance提供getter方法
public double getBalance() {
return balance;
}
//提供一个线程安全的draw()方法来完成取钱操作
public void draw(double drawAmount){
lock.lock();
try {
if(!flag){
cond.await();
}else{
//执行取钱操作
System.out.println(Thread.currentThread().getName()+"取钱"+drawAmount);
balance -= drawAmount;
System.out.println("账户余额为:"+balance);
flag = false;
//唤醒其他线程
cond.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally{
lock.unlock();
}
}
public void deposit(double depositAmount){
lock.lock();
try {
//flag为true 表示账户已有人存钱进去,存钱方法阻塞
//当while判断后,wait()方法释放锁,唤醒其他线程去存钱,当存取次数相同时,此程序不会阻塞
// while(flag){
// wait();
// }
if(flag){
cond.await();
}else{
//执行存款操作
System.out.println(Thread.currentThread().getName()+"存款:"+ depositAmount);
balance += depositAmount;
System.out.println("账户余额:"+balance);
flag = true;
cond.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally{
lock.unlock();
}
}
}
class DrawThread extends Thread{
//模拟用户取钱
private Account account;
//当前取钱线程所希望取的钱数
private double drawAmount;
public DrawThread(String name,Account account,double drawAmount){
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
public void run(){
for (int i = 0; i < 300; i++) {
System.out.println("取钱次数"+i);
account.draw(drawAmount);
}
}
}
![]()
![]()
![]()
public class BlockingQueueTest {
public static void main(String[] args) {
//创建一个容量为1的BlockingQueue
BlockingQueue<String> bq = new ArrayBlockingQueue<>(1);
//产生3个生产者线程
new Producer(bq).start();
new Producer(bq).start();
new Producer(bq).start();
//启动一个消费者线程
new Consumer(bq).start();
}
}
class Producer extends Thread{
private BlockingQueue<String> bq;
public Producer(BlockingQueue<String> bq){
this.bq = bq;
}
public void run(){
String[] strArr = new String[]{"Java","Struts","Spring"};
for (int i = 0; i < 999999999; i++) {
System.out.println(getName() + "生产者准备生产集合元素");
//尝试放入元素,如果队列已满,则线程被阻塞
try {
Thread.sleep(200);
bq.put(strArr[i % 3]);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"生产完成"+bq);
}
}
}
class Consumer extends Thread{
private BlockingQueue<String> bq;
public Consumer(BlockingQueue<String> bq){
this.bq = bq;
}
public void run(){
while(true){
System.out.println(getName() + "消费者准备消费集合元素!");
try {
Thread.sleep(200);
bq.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"消费完成"+bq);
}
}
}
线程组和未处理的异常:
![]()
![]()
![]()
![]()
public class ThreadGroupTest {
public static void main(String[] args) {
//获取主线程所在的线程组,这是所有线程默认的线程组
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("主线程祖的名字:"+mainGroup.getName());
System.out.println("主线程是否是后台线程组"+mainGroup.isDaemon());
new MyThread("主线程组的线程").start();
ThreadGroup tg = new ThreadGroup("新线程组");
tg.setDaemon(true);
System.out.println("tg线程组是否是后台线程组"+tg.isDaemon());
MyThread tt = new MyThread(tg,"tg线程甲");
tt.start();
new MyThread(tg,"tg组的线程乙").start();
}
}
class MyThread extends Thread{
//提供指定线程名的构造器
public MyThread(String name){
super(name);
}
//提供指定线程名、线程组的构造器
public MyThread(ThreadGroup group , String name){
super(group,name);
}
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println(getName() + "线程的i变量"+i);
}
}
}
![]()
![]()
public class ExHandler {
public static void main(String[] args) {
//设置主线程的异常处理器
Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler());
int a = 5/0;
System.out.println("线程正常结束");
}
}
class MyExHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t+"线程出现了异常:"+e);
}
}
![]()
线程池:
![]()
![]()
![]()
![]()
public class ThreadPoolTest {
public static void main(String[] args) throws Exception{
//创建一个具有固定线程数6的线程池
ExecutorService pool = Executors.newFixedThreadPool(6);
//使用lambda表达式创建Runnable对象
Runnable target = () -> {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"i值:"+i);
}
};
//向线程池中提交两个线程
pool.submit(target);
pool.submit(target);
//关闭线程池
pool.shutdown();
}
}
![]()
![]()
public class ForkJoinPoolTest {
public static void main(String[] args) throws Exception {
ForkJoinPool pool = new ForkJoinPool();
//提交可分解的PrintTask任务
pool.submit(new PrintTask(0,300));
pool.awaitTermination(2, TimeUnit.SECONDS);
//关闭线程池
pool.shutdown();
}
}
class PrintTask extends RecursiveAction{
private static final long serialVersionUID = 1L;
//每个“小任务”最多打印50个数
private static final int THRESHOLD = 50;
private int start;
private int end;
//打印从start到end的任务
public PrintTask(int start,int end){
this.start = start;
this.end = end;
}
@Override
protected void compute() {
//当end与start之间的差小于THRESHOLD时,开始打印
if(end - start < THRESHOLD){
for (int i = start ; i < end; i++) {
System.out.println(Thread.currentThread().getName()+"i的值:"+i);
}
}else{
//当end与start之间的差大于Threshold,即要打印的数超过50个时
//将大任务分解成两个”小任务“
int middle = (start + end)/2;
PrintTask left = new PrintTask(start, middle);
PrintTask right = new PrintTask(middle, end);
//并行执行两个”小任务“
left.fork();
right.fork();
}
}
}
![]()
public class Sum {
public static void main(String[] args) throws Exception{
int[] arr = new int[100];
Random rand = new Random();
int total = 0;
//初始化100个数字元素
for (int i = 0,len = arr.length; i < len; i++) {
int tmp = rand.nextInt(20);
//对数组的元素赋值,并将数组元素的值添加到sum总和中
total += (arr[i] = tmp);
System.out.println(arr[i]);
}
System.out.println(total);
//创建一个通用池
ForkJoinPool pool = ForkJoinPool.commonPool();
//提交可分解的CaltTask任务
Future<Integer> future = pool.submit(new CalTask(arr,0,arr.length));
System.out.println(future.get());
//关闭线程池
pool.shutdown();
}
}
class CalTask extends RecursiveTask<Integer>{
//每个"小任务"最多只累加20个数
private static final int THRESHOLD = 20;
private int arr[];
private int start;
private int end;
//累加从start到end的数组元素
public CalTask(int[] arr , int start , int end){
this.arr = arr;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
//当end 与 start 之间的差小于THRESHOLD时,开始进行累加
if(end - start < THRESHOLD){
for(int i = start; i < end ;i++){
sum += arr[i];
}
return sum;
}else{
//当end与start之间的差大于THRESHOLD,即要累加的数超过20个小时
//将大任务分解成两个"小任务"
int middle = (start + end) /2;
CalTask left = new CalTask(arr,start,middle);
CalTask right = new CalTask(arr,middle,end);
//并行执行两个"小任务"
left.fork();
right.fork();
//把两个"小任务"累加的结果合并起来
return left.join() + right.join();
}
}
}
线程相关类:
![]()
![]()
public class ThreadLocalTest {
public static void main(String[] args) {
//启动两个线程,两个线程共享一个TAccount
TAccount at = new TAccount("初始名");
/**
* 虽然两个线程共享一个账户,即只有一个账户名
* 但由于账户名是ThreadLocal类型的,所以每个线程都完全拥有
* 各自的账户名副本。因此在i==6之后,将看到两个线程访问同一个
* 账户时出现不同的账户名
*/
new MyTest(at,"线程甲").start();
new MyTest(at,"线程乙").start();
}
}
class TAccount{
//定义一个ThreadLocal类型的变量,该变量将是一个线程局部变量
//每个线程都会保留该变量的一个副本
private ThreadLocal<String> name = new ThreadLocal<String>();
//定义一个初始化name成员变量的构造器
public TAccount(String str){
this.name.set(str);
System.out.println("-----" + this.name.get());
}
public String getName() {
return name.get();
}
public void setName(String str) {
this.name.set(str);;
}
}
class MyTest extends Thread{
//定义一个Account类型的成员变量
private TAccount account;
public MyTest(TAccount account , String name){
super(name);
this.account = account;
}
public void run(){
//循环10次
for (int i = 0; i < 10; i++) {
//当i==6时输出将账户名替换成当前线程名
if(i==6){
account.setName(getName());
}
//输出同一个账户的账户名和循环变量
System.out.println(account.getName()+" 账户的i值 "+i);
}
}
}
![]()
![]()
![]()
![]()
快速创建两种线程:
public class Test00 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//第一种:
new Thread("我是线程1"){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}.start();
//第二种:
new Thread(new Runnable(){ //匿名内部类的实质是创建该类或接口的子类对象
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
},"我是线程2").start();
}
}
定时器:
![]()
![]()
![]()
/**
* 需求:在指定时间删除指定目录
* @author
*
*/
public class TimerDemo {
public static void main(String[] args) throws ParseException {
Timer t = new Timer();
String s = "2017-8-15 9:42:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);
t.schedule(new DeleteFolder(),d);
}
}
class DeleteFolder extends TimerTask{
@Override
public void run() {
File srcFolder = new File("demo");
deleteFolder(srcFolder);
}
//递归删除目录
public void deleteFolder(File srcFolder){
File[] fileArr = srcFolder.listFiles();
if(fileArr != null){
for(File file:fileArr){
if(file.isDirectory()){
deleteFolder(file);
}else{
System.out.println(file.getName()+":"+file.delete());
}
}
System.out.println(srcFolder.getName()+":"+srcFolder.delete());
}
}
}