标签:新特性 The 输出流 线程的生命周期 lock rac exception 进程与线程 ++i
导读:java多线程编程不太熟?或是听说过?或是想复习一下?找不到好的文章?别担心我给你们又安利一波,文章内容很全,并且考虑到很多开发中遇到的问题和解决方案。循环渐进,通俗易懂,文章较长,建议收藏再看!
往期精彩放送:一文搞定Java的输入输出流等常见流
package Day3;
public class ThreadTest1 {
public static void main(String[] args) {
System.out.println("main begin");
m1();
System.out.println("main end");
}
private static void m1(){
System.out.println("m1 begin");
m2();
System.out.println("m1 end");
}
private static void m2(){
System.out.println("m2 begin");
m3();
System.out.println("m2 end");
}
private static void m3(){
System.out.println("m3 begin");
System.out.println("m3 end");
}
}
package Day3;
//第一种:直接继承Thread
public class ThreadTest2 {
public static void main(String[] args) {
//这里是主线程,在主栈中执行
//新建一个分支线程
MyThread myThread = new MyThread();
//启动线程
/*start方法的作用:启动一个分支线程,在JVM种开辟一个新的栈空
间,这段代码完成后瞬间就结束了,线程就启动成功了*/
/*启动成功的线程会自动调用run方法,并且run方法在分支栈的底部
run和main方法平级*/
myThread.start();
//myThread.run();//不会启动动线程(为单线程)
for(int i=0 ;i<100;i++){
System.out.println("主线程--->"+i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
//编写代码,这段程序在分支线程中执行
for(int i=0 ;i<100;i++){
System.out.println("分支线程--->"+i);
}
}
}
package Day3;
public class ThreadTest3 {
public static void main(String[] args) {
//创建一个线程的对象
MyRunnable aa = new MyRunnable();
//将可运行的对象封装成一个线程对象
Thread t =new Thread(aa);
//启动线程
t.start();
for(int i =0 ;i<1000;i++){
System.out.println("主线程-->"+i);
}
}
}
//这并不是一个线程类,是一个可运行的类,他还不是一个线程
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i =0 ;i<1000;i++){
System.out.println("分支线程-->"+i);
}
}
}
package Day3;
public class ThreadTest4 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {//new一个对象,且实现了Runnable接口
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("分支线程--->" + i);
}
}
});
//启动线程
t.start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程--->" + i);
}
}
}
package Day3;
public class ThreadTest5 {
public static void main(String[] args) {
//以下代码出现在main方法中,所以当前线程就是主线程,获取当前线程对象
Thread current1 = Thread.currentThread();
System.out.println(current1.getName());
//创建线程对象
MyThread2 t1 = new MyThread2();
//设置线程的名字
t1.setName("sss");
//获取线程的名字
System.out.println(t1.getName());
//创建线程对象
MyThread2 t2 = new MyThread2();
System.out.println(t2.getName());
//启动线程
t1.start();
for(int i=0;i<10;i++){
Thread current2 = Thread.currentThread();
System.out.println(current2.getName()+"-->"+i);
}
}
}
class MyThread2 extends Thread{
@Override
public void run() {
//获取当前对象
for (int i =0;i<1000;i++){
//获取当前线程对象
Thread current2 = Thread.currentThread();
System.out.println(current2.getName()+"--->"+i);
}
}
}
package Day3;
public class ThreadTest10 {
public static void main(String[] args) {
System.out.println("main begin!");
Thread f = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
});
f.setName("ttt");
f.start();
//合并到当前线程,当前线程受到阻塞,直到f线程执行结束
try {
f.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main over!");
}
}
运行部分结果:
package Day3;
public class ThreadTest8 {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable3());
t.setName("t");
t.start();
for(int i =0;i<1000;i++){
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
class MyRunnable3 implements Runnable{
@Override
public void run() {
for(int i =0;i<=1000;i++) {
if (i %100==0){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
package Day3;
public class TreadTest6 {
public static void main(String[] args) {
//让当前线程睡眠10秒,主线程
try {
for(int i=0;i<10;i++) {
System.out.println("Hello Wrold!");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package Day3;
public class ThreadTest7 {
public static void main(String[] args) {
Thread t =new Thread(new Runnable() {//匿名内部类实现接口
@Override
public void run() {
try {
Thread.sleep(1000*60*60);
} catch (InterruptedException e) {//interrupted()方法引发这个异常
e.printStackTrace();
}
System.out.println("Hello Wrold!");
}
});
t.setName("se");
t.start();
t.interrupt();//中断阻塞
}
}
package Day3;
import java.util.concurrent.ThreadLocalRandom;
public class ThreadTest9 {
public static void main(String[] args) {
MyRunnable2 r =new MyRunnable2();//需要对象,合理终止需要用到对象的属性
Thread t = new Thread(r);
t.setName("Jia");
t.start();
try {
Thread.sleep(5*1000);//5秒后终止线程
} catch (InterruptedException e) {
e.printStackTrace();
}
//暴力终止t线程`
//t.stop();//缺点:线程没有保存的数据会丢失,即容易丢失数据(已过时
//合理终止线程的执行,标记法
r.run=false;
}
}
class MyRunnable2 implements Runnable{
//run标记
boolean run =true;
@Override
public void run() {
for(int i =0;i<10;i++){
if(run) {
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
//终止线程
return;
}
}
}
}
package Day1;
public class AccountTest1 {
public static void main(String[] args) {
Account account = new Account("Jia",10000);
//创建两个线程对象
Thread t1 = new MyAccountThread(account);
Thread t2 = new MyAccountThread(account);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class Account {
private String name;
private double blance;
public Account() {
}
public Account(String name, double blance) {
this.name = name;
this.blance = blance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getBlance() {
return blance;
}
public void setBlance(double blance) {
this.blance = blance;
}
//取款
public void GetMoney(double money){
//两个线程并发,同时操作堆中的对象
//取款之前
double before =this.getBlance();
//取款之后
double after = before -money;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果t1线程执行到这之前余额还没更新,t2也进来执行获取余额了,这时就会出问题
this.setBlance(after);
}
}
class MyAccountThread extends Thread{
//两个线程共享一个账户对象
private Account account1 ;
//通过构造方法传递过来账户对象
public MyAccountThread(Account account1) {
this.account1 = account1;
}
@Override
public void run() {
//取款5000
double money =5000;
account1.GetMoney(money);
System.out.println("取款成功!"+"账户"+account1.getName()+"余款:"+account1.getBlance());
}
}
运行结果:取了两次钱结果:
说明:不同的类尽量写在不同的源文件中。这里是为了便于观察。
package Day1;
//使用同步机制解决线程安全问题
public class AccountTest1 {
public static void main(String[] args) {
Account account = new Account("Jia",10000);
//创建两个线程对象
Runnable tt1= new MyAccountThread(account);//多态
Runnable tt2 = new MyAccountThread(account);
Thread t1 = new Thread(tt1);
Thread t2 = new Thread(tt2);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class Account {
private String name;
private double blance;
public Account() {
}
public Account(String name, double blance) {
this.name = name;
this.blance = blance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getBlance() {
return blance;
}
public void setBlance(double blance) {
this.blance = blance;
}
//取款
public void GetMoney(double money){
//以下代码必须是线程排队的,不能并发
//一个线程吧这里的代码全部执行后,另一个才能进来执行
/*synchronized后面小括号”数据很关键“,必须是多线程共享的数据,才能排队
小括号写什么看你想要哪几个线程同步,例如t1,t2..t5,如果你只希望t1,t2,t3,排队
你一定要在括号中写一个t1,t2,t3共享的对象。t4,t5不共享这个对象,就可以并发执行。*/
synchronized (this) {//线程同步机制,线程同步代码块,需要传入共享资源;共享资源的不同,决定了什么不同的线程同步
double before = this.getBlance();//这里写什么,取决于你想对于什么资源,对应的线程排队。
double after = before - money;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBlance(after);
}
}
}
class MyAccountThread implements Runnable{
//两个线程共享一个账户对象
private Account account1 ;
//通过构造方法传递过来账户对象
public MyAccountThread(Account account1) {
this.account1 = account1;
}
@Override
public void run() {
//取款5000
double money =5000;
account1.GetMoney(money);
System.out.println("取款成功!"+"账户"+account1.getName()+"余款:"+account1.getBlance());
}
}
运行结果:
package Day1;
import java.util.concurrent.SynchronousQueue;
public class ExamTest1 {
//死锁要会写
public static void main(String[] args) {
//两个线程共享o1,o2
Object o1 = new Object();
Object o2 = new Object();
Thread t1 = new MyThread1(o1,o2);
Thread t2 = new MyThread2(o1,o2);
t1.start();
t2.start();
}
}
class MyThread1 extends Thread {
Object o1;
Object o2;
public MyThread1(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
synchronized (o1) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
}
}
}
}
class MyThread2 extends Thread {
Object o1;
Object o2;
public MyThread2(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
synchronized (o2) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
}
}
}
}
package Day1;
public class TheadTest1 {
public static void main(String[] args) {
Thread JiSi=new MyDaemon();
JiSi.setName("备份数据");
//设为守护线程
JiSi.setDaemon(true);
JiSi.start();
//主线程
for(int i =0 ;i<10;i++){
System.out.println(Thread.currentThread().getName()+"-->"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyDaemon extends Thread{
@Override
public void run() {
int i = 0;
//即使是死循环,但由于改线程是守护者,当用户结束,守护线程自动终止。
while (true) {
System.out.println(Thread.currentThread().getName() + "-->" + (++i));
try {
Thread.sleep(1000);//模拟一秒记录一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
从结果可以看出当用户线程结束的时候,守护线程也终止。
package Day2;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.AbstractMap;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.zip.DataFormatException;
public class TimerTest1 {
public static void main(String[] args) {
//创建定时器对象
Timer timer =new Timer();
//Timer timer = new Timer(true);//守护线程的方式
//定时任务
//timer.schedule(定时任务,第一次执行时间,间隔多久一次)//定时任务属于,TimerTask类
//创建对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
//将时间字符串转换成可处理的时间
Date firstTime = sdf.parse("2020-04-11 10:40:00");
timer.schedule(new LogTimerTask(),firstTime,1000*5);//每隔5秒备份一次
} catch (ParseException e) {
e.printStackTrace();
}
}
}
//设为定时任务类,假设为记录日志的定时任务
class LogTimerTask extends TimerTask{//TimerTask为抽象类,因为任务的类型为这个类
@Override
public void run() {
//创建一个日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(new Date());//将当前系统时间转换为字符串
System.out.println(strTime+"成功完成了一次数据备份!");
}
}
部分运行结果:
package Day2;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//实现Callable接口,实现线程的第三种方式
public class CallableTest1 {
public static void main(String[] args) {
//第一步:创建一个“未来任务类”对象
FutureTask task =new FutureTask(new Callable() {//匿名内部类实现接口
@Override
public Object call() throws Exception {//相当于run方法,只不过有返回值
//线程执行一个任务,可能有一个执行结果
System.out.println("Call method begin!");
Thread.sleep(1000*5);
System.out.println("Call method over!");
int a,b;
a=100;
b=200;
return a+b;//自动装箱(Interger)
}
});
//创建线程对象
Thread t = new Thread(task);
//启动线程
t.start();
//这里时main方法,在主线程
//用get()方法,获取t线程的返回结果,但是当前线程受到阻塞
Object obj = null;
try {
obj = task.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//主线程要执行以下程序必须等待get()方法执行结束。
System.out.println("线程执行结果:"+obj);
System.out.println("Hello World!");
}
}
package Day2;
import java.util.ArrayList;
import java.util.List;
//List模拟仓库,容量为1,即生产一个消费一个
public class ProductTest1 {
public static void main(String[] args) {
//创建一个仓库对象,共享的
List list = new ArrayList();
//创建两个线程对象
//生产者线程
Thread t1 = new Thread(new Producer(list));
//消费者线程
Thread t2 = new Thread(new Consumer(list));
t1.setName("生产者线程:");
t2.setName("消费者线程:");
t1.start();
t2.start();
}
}
//生产线程
class Producer implements Runnable{
//仓库
private List list;
public Producer(List list) {
this.list = list;
}
@Override
public void run() {
//一直生产
while(true) {
synchronized (list) {//给仓库资源加锁
if (list.size() > 0) {
//当前线程进入等待状态,释放锁,不放锁的话,消费者线程无法访问资源(生产者线程)
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序能执行到这里说明仓库为空,可以生产
Object obj = new Object();
list.add(obj);
System.out.println(Thread.currentThread().getName()+"-->"+obj);
//唤醒消费者消费
list.notify();
}
}
}
}
//消费线程
class Consumer implements Runnable{
//同一个仓库
private List list;
public Consumer(List list) {
this.list = list;
}
@Override
public void run() {
//一直消费
while (true){
synchronized (list){//没有得到锁,以下代码都不能执行
if(list.size()==0){
//仓库空了,停止消费,消费线程进入阻塞,释放list集合的锁
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序能够执行到这,说明仓库有数据,进行消费
Object obj= list.remove(0);
System.out.println(Thread.currentThread().getName()+"-->"+obj);
//唤醒生产者进行生产
list.notify(