您的位置:首页 > 编程语言 > Java开发

JAVA进阶知识点总结 6-线程 同步 线程状态

2019-03-29 19:44 621 查看

01.第一章:多线程_回顾实现线程的方式一:

1).定义一个线程类,继承自Thread,重写run()方法;

class MyThread extends Thread{
public void run(){
...
}
}

2).启动线程
1).创建我们定义线程类的对象;
2).调用对象的start()方法启动线程;

main(){
MyThread t = new MyThread();
t.start();
//	t.run();//只是普通的方法调用
}

02.第一章:多线程_多线程的运行原理:

03.第一章:多线程_Thread类的常用方法_构造方法:

1).构造方法:

1).Thread():无参构造方法
2).Thread(String name):使用一个线程名称构造一个线程对象
每个线程都有一个默认的线程名:Thread-索引值 通过getName()方法可以获取线程名称
3).Thread(Runnable run):使用一个Runnable的实现类构造一个线程对象; 在“创建线程的方式二”中演示
4).Thread(Runnable run,String name):使用一个Runnable和一个线程名称构造一个线程对象。

03.第一章:多线程_Thread类的常用方法_成员方法:

1).public String getName():获取线程的名称;
2).public static void sleep(long millis):让当前线程休眠指定的毫秒值;

public class MyThread extends Thread {
@Override
public void run() {
for (; ; ) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(date);
System.out.println(str);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

3).public static Thread currentThread():获取当前的线程对象;

public class Demo {
public static void main(String[] args) {
//主线程也是一个线程,是由JVM来启动的
//主线程也有线程名
//Thread.currentThread()可以获取当前的线程对象,然后调用getName()就能获取线程名称
for (int k = 0; k < 100; k++) {
System.out.println(Thread.currentThread().getName() + " k = " + k);

}
}
}

04.第一章:多线程_制作线程的方式二_Runnable接口:

1).定义一个子类,实现Runnable接口,重写run()方法;
/*
注意:实现Runnable后,我们的类–不是一个线程类
后期必须要委托给一个线程类Thread去执行
*/

public class MyRun implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " i = " + i);

}
}
}

2).启动线程:
1).创建一个自定义Runnable子类对象;
2).创建一个Thread对象,并将自定义对象作为参数传给Thread的构造方法;
3).调用Thread的start()方法启动线程。它内部会去调用我们自定义对象内部的run()方法。
示例代码:

public class Demo {
public static void main(String[] args) {
MyRun myRun = new MyRun();

Thread t1 = new Thread(myRun,"章子怡");
Thread t2 = new Thread(myRun,"汪峰");

t1.start();
t2.start();

}
}

05.第一章:多线程_两种实现方式的区别:

1).第一种:继承自Thread.由于Java单继承的限制,对于子类形成了制约。
2).第二种:实现接口Runnable。子类可以同时实现多个接口【建议使用】

06.第一章:匿名内部类的方式实现线程:

1).匿名内部类的格式:

new 父类/父接口名(){
//子类的类体
}

2).实现线程的方式一,使用匿名内部类的方式:
new Thread(){//Thread的子类类体}.start();
示例代码:

public static void main(String[] args) {
//Thread t = new Thread的匿名子类对象();
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
}
}
}.start();

//主线程继续
for (int k = 0; k < 100; k++) {
System.out.println("k = " + k);
}
}

2).实现线程的方式二,使用匿名内部类的方式:
new Thread(Runnable子类对象).start();
示例代码:

new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
}
}
}).start();

07.第一章:多线程安全性问题:

1).多线程安全性问题产生的原因:多个线程同时访问同一个变量;
2).示意图:

3).代码:
1.定义一个类,实现Runnable接口:
/*
注意:实现Runnable后,我们的类–不是一个线程类
后期必须要委托给一个线程类Thread去执行
*/

public class MyRun implements Runnable {
int a = 100;
@Override
public void run() {//线程1,线程2
for (int i = 0; i < 100; i++) {//线程1(1,2)//线程2(1,2,3)//线程1(3)
a++;//1.将a的值100取出到运算器中;2.在运算器中计算 100 + 1 ;3.将101赋给a
}
System.out.println("线程执行完毕!");
}
}

2.测试类:

public class Demo {
public static void main(String[] args) throws InterruptedException {
MyRun myRun = new MyRun();

Thread t1 = new Thread(myRun,"章子怡");
Thread t2 = new Thread(myRun,"汪峰");

t1.start();
t2.start();

//主线程休息一秒,确保上面的两个线程执行完毕
Thread.sleep(1000);

//获取最终的结果
System.out.println(myRun.a);//正常:300

}
}

08.第二章:多线程售票模拟线程安全性问题:
1).定义Tickets类:

public class Tickets implements Runnable {
private int tickets = 100;
@Override

public void run() {
//死循环
while (true){
//判断是否有票
if (tickets > 0) {
//取一张
int t = tickets;
try {
Thread.sleep(1);//目的:让效果更明显,让其它线程运行
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;

System.out.println(Thread.currentThread().getName() +
" 取走一张票:" + t);
}else{
System.out.println("没票了!");
break;
}
}
}
}

2).定义测试类:

public class Demo {
public static void main(String[] args) {
//1.创建一个Tickets对象
Tickets t = new Tickets();

//2.创建两个线程
Thread t1 = new Thread(t,"窗口1");
Thread t2 = new Thread(t,"窗口2");

t1.start();
t2.start();

}
}

09.第二章:同步代码块_解决多线程售票线程安全性问题:

1).格式:
synchronized(锁对象){
//同步代码
}
锁对象:可以是任何对象,但必须保证多个线程共同使用同一个锁对象。
2).示例代码:
1).修改Tickets类:

public class Tickets implements Runnable {
private int tickets = 100;
private Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if (tickets > 0) {
int t = tickets;
try {
Thread.sleep(1);//目的:让效果更明显
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;

System.out.println(Thread.currentThread().getName() +
" 取走一张票:" + t);
}else{
System.out.println("没票了!");
break;
}
}//一个线程执行完毕,会自动释放锁

}
}
}

2).主线程类:

public class Demo {
public static void main(String[] args) {
//1.创建一个Tickets对象
Tickets t = new Tickets();

//2.创建两个线程
Thread t1 = new Thread(t,"窗口1");
Thread t2 = new Thread(t,"窗口2");

t1.start();
t2.start();

}
}

10.第二章:同步方法_解决多线程售票线程安全性问题【常用】:

1).格式:
//同步方法,使用的锁对象是:this
public synchronized int getTicket(){
//同步代码
}
2).示例代码:
1).修改Tickets类即可:

public class Tickets implements Runnable {
private int tickets = 100;
@Override
public void run() {
while (true){
int t = this.getTicket();
if (t > 0) {
System.out.println(Thread.currentThread().getName() +
" 取走一张票:" + t);

}else{
System.out.println("没票了!!");
break;
}
}
}
//同步方法,使用的锁对象是:this
public synchronized int getTicket() {
if (tickets > 0) {
int t = tickets;
try {
Thread.sleep(1);//目的:让效果更明显
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;
return t;
} else {
return 0;
}
}
}

11.第二章:Lock锁_解决多线程售票线程安全性问题:

1).格式:

Lock l = new 某个实现类对象();
l.lock();//加锁
try {
//同步代码
} finally {
l.unlock(); //解锁
}

2).示例代码:

public class Tickets implements Runnable {
private int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();//加锁
try {
if (tickets > 0) {
int t = tickets;
try {
Thread.sleep(1);//目的:让效果更明显
} catch (InterruptedException e) {
e.printStackTrace();
}
tickets--;

System.out.println(Thread.currentThread().getName() + " 取走一张票:" + t);
} else {
System.out.println("没票了!");
break;
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
}

12.第三章:线程状态:

13.第三章:线程状态_无限等待_wait方法:

public class Demo {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();

new Thread(){
@Override
public void run() {
synchronized (obj) {
for (int i = 0; i < 20; i++) {
System.out.println("i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 10) {
//让当前的线程挂起,等待被唤醒
try {
System.out.println("我开始等待...");
obj.wait();//会立即释放obj锁
System.out.println("我醒了,开始干活了....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}.start();
//开启一个新线程
new Thread(){
@Override
public void run() {
//获取obj锁对象
System.out.println("第二个线程开始执行...");
synchronized (obj){
//唤醒所有在obj锁上等待线程.
System.out.println("第二个线程开始唤醒....");
obj.notifyAll();//唤醒后,
}//唤醒后,会释放锁
}
}.start();
}}

14.第三章:线程状态_无限等待_包子铺案例:

=======================================================================
学习目标总结:
01.能够描述Java中多线程运行原理
每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈

02.能够使用继承类的方式创建多线程

class MyThread extends Thread{
public void run(){
//...
}
}
main(){
MyThread t = new MyThread();
t.start();
t.run();//普通的方法调用
t.start();//抛异常
}

03.能够使用实现接口的方式创建多线程

class MyRun implements Runnable{
public void run(){
//...
}
}
main(){
MyRun myRun = new MyRun();
Thread t = new Thread(myRun);
t.start();
}

04.能够说出实现接口方式的好处
1).解决单继承的限制。

05.能够解释安全问题的出现的原因
1).多个线程同时访问同一个变量;

06.能够使用同步代码块解决线程安全问题
synchronized(锁对象){
//同步代码
}
07.能够使用同步方法解决线程安全问题

public synchronized void show(){
//同步代码
}

08.能够说出线程6个状态的名称
1.新建
2.可运行
3.计时等待
4.锁阻塞
5.无限等待
6.被终止
09.能够理解等待唤醒案例

public static void main(String[] args) throws InterruptedException {
Object obj = new Object();

new Thread(){
@Override
public void run() {
synchronized (obj) {
for (int i = 0; i < 20; i++) {
System.out.println("i = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 10) {
//让当前的线程挂起,等待被唤醒
try {
System.out.println("我开始等待...");
obj.wait();//会立即释放obj锁
System.out.println("我醒了,开始干活了....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}.start();
//开启一个新线程
new Thread(){
@Override
public void run() {
//获取obj锁对象
System.out.println("第二个线程开始执行...");
synchronized (obj){
//唤醒所有在obj锁上等待线程.
System.out.println("第二个线程开始唤醒....");
obj.notifyAll();//唤醒后,
}//唤醒后,会释放锁
}
}.start();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐