目录
- 1.多线程概述
- 2.实现线程的两种方式
- 3.线程生命周期
- 4.获取线程的名字
- 5.获取当前线程对象
- 6.关于sleep()方法
- sleep()实例
- 7.关于sleep()的面试题
- 8.sleep()方法与wait()方法的区别
- 9.终止线程的休眠 .interrupt()
- 10.强行终止线程 .stop() (已过时)
- 11.合理终止线程的方式
- 12.线程调度概述(了解)
- 13.关于多线程并发环境下,数据的安全问题
- 14. 两个线程对同一个账户的取款实例(线程安全)
- 15.对synchronized的理解
- 16.哪些变量有线程安全问题
- 17.synchronized面试题
- 18.死锁现象概述
- 19.开发中怎么解决线程安全问题
- 20.守护线程(后台线程)
- 21.定时器
- 22.实现线程的第三种方式(实现Callable接口)
- 23.wait() 和 notify()
- 24.生产者和消费者模式
- Lock锁
1.多线程概述
2.实现线程的两种方式
建议使用接口方式
1.实现线程方法一(继承Thread,重写run)
start()方法的作用是:启动一个分支线程,在JVM中开辟一个新的空间,这段代码任务完成之后,瞬间就结束了。此时线程就启动成功了。
2.run()和start()的区别
run()
start()
3.实现线程方法二(实现Runable接口)
采用匿名内部类方式
3.线程生命周期
4.获取线程的名字
5.获取当前线程对象
6.关于sleep()方法
sleep()实例
public class Main {
public static void main(String[] args) throws IOException {
MyRunable myRunable= new MyRunable();
Thread t1=new Thread(myRunable);//实例化线程
t1.setName("t1");
t1.start();
try {
Thread.sleep(1000*7);//主线程 休眠 7秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->end");//主线程结束
}
}
class MyRunable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--> begin");//线程开始
try {
Thread.sleep(1000*3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println("分支线程-->"+i);
}
System.out.println(Thread.currentThread().getName()+"-->end");
}
}
运行过程:在主线程创建线程 t1—> t1线程就绪 —>主线程开始休眠7秒–>主线程休眠的同时分支线程t1抢到时间片,运行线程t1—>t1先休息3秒再进行输出—>t1结束后,主线程还没有完成7秒休眠,将剩下的时间完成后,再开始继续主线程。
7.关于sleep()的面试题
答案:不可以
由源代码可知,sleep()是一个静态方法。作用是让当前 面线程休眠,出现在main方法中,所以 主线程休眠。(出现在哪个里 ,哪个休眠)
8.sleep()方法与wait()方法的区别
这是一个常见的面试题,比较重要,也比较好理解。
1.相同点:
(1)这两个方法都能使线程进入阻塞状态
2.不同点:
(1)sleep()方法是Thread类中的静态方法;而wait()方法是Object类中的方法;
(2)sleep()方法可以在任何地方调用;而wait()方法只能在同步代码块或同步方法中使用(即使用synchronized关键字修饰的);
(3)这两个方法都在同步代码块或同步方法中使用时,sleep()方法不会释放同步监视器;而wait()方法则会释放同步监视器;
9.终止线程的休眠 .interrupt()
使用 .interrupt(); 这种终止休眠的方式已考虑java的异常处理机制
10.强行终止线程 .stop() (已过时)
11.合理终止线程的方式
在else中 进行数据存储,以防丢失
12.线程调度概述(了解)
线程让位 .yield()
//线程让位
public class Main {
public static void main(String[] args) throws IOException {
MyRunable myRunable= new MyRunable();
Thread t1=new Thread(myRunable);
t1.setName("t1");
t1.start();
for (int i = 1; i<=1000; i++) {
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
class MyRunable implements Runnable{
boolean run=true;
@Override
public void run() {
for (int i = 1; i <=1000 ; i++) {
if(i%100==0){
Thread.yield();//当前线程暂停一下,让给主线程
}
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
线程合并
13.关于多线程并发环境下,数据的安全问题
14. 两个线程对同一个账户的取款实例(线程安全)
出错实例
两个线程对同一账户进行取款 ,如果出现线程1取完款但还没有进行更新余额时(网络延迟),正好线程2也去取款这种情况。此时就会出现线程安全问题
public class Main {
public static void main(String[] args) throws InterruptedException {
Account account=new Account(1,12000);
MyThread t1=new MyThread(account);
MyThread t2=new MyThread(account);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
public class Account {//账户类
private int number;//账号
private float balance;//余额
public Account() {
}
public Account(int number, float balance) {
this.number = number;
this.balance = balance;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public float getBalance() {
return balance;
}
public void setBalance(float balance) {
this.balance = balance;
}
//进行取款,并更新余额
public void getMoney( float limit){
float before=this.getBalance();
float after=before-limit;
try {
Thread.sleep(500);//模拟网络延迟,导致还没更新余额,另一个线程就进来取款的方法,此时一定出错
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);//更新余额
}
}
public class MyThread extends Thread{//线程类
private Account act;//账户对象
public MyThread() {
}
public MyThread(Account act) {
this.act = act;
}
public Account getAct() {
return act;
}
public void setAct(Account act) {
this.act = act;
}
@Override
public void run() {
//取款
float limit=5000;//取款额
act.getMoney(limit);//调用取款方法
System.out.println(Thread.currentThread().getName()+"从账号"+ act.getNumber()+"取款"+limit+",账户余额"+act.getBalance());
}
}
解决方法(采用线程同步机制)
15.对synchronized的理解
同步代码块越小,效率约高
synchronized出现在实例方法上
synchronized三种写法
16.哪些变量有线程安全问题
17.synchronized面试题
1.
2.
因为synchronized 在实例方法上时,锁的this。在main中两个线程调用的同一个MyClass对象 mc ,所以当t2在执行doOther时,this被doSome锁住了 ,10秒后才会放锁,所以 需要等待。
3.
4.
18.死锁现象概述
T1从上往下执行,先锁上面的对象。T2从下往上执行,当T1去锁下面的对象时,对象已经被T2锁住了,T2去锁上面的对象时,被T1占用。--------此时便是死锁的状态。
死锁会让程序停在那,不出异常也不出错误。
public class Test {
public static void main(String[] args) {
//创建两个对象,创建两个线程。分别对两对象进行访问,一个先访问o1,另一个先o2.
Object o1 = new Object();
Object o2= new Object();
MyTread t1= new MyTread(o1,o2);
MyTread2 t2= new MyTread2(o1,o2);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class MyTread extends Thread{
Object o1;
Object o2;
public MyTread() {
}
public MyTread(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
synchronized (o1){
try {
Thread.sleep(1000);//锁住o1,进行休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){
}
}
}
}
class MyTread2 extends Thread{
Object o1;
Object o2;
public MyTread2() {
}
public MyTread2(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
synchronized (o2){//先o2再o2
try {
Thread.sleep(1000);//锁住o2,进行休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
}
}
}
}
19.开发中怎么解决线程安全问题
20.守护线程(后台线程)
1.概述
2.实现守护线程
21.定时器
22.实现线程的第三种方式(实现Callable接口)
23.wait() 和 notify()
24.生产者和消费者模式
Lock锁