Java 第十章线程(2)
目录
多线程
编辑
概念
多线程优点:
多线程的缺点:
线程同步
实例
同步锁
特点:
实例:
线程通信
实例1
实例2
新增创建线程方式
多线程
概念
多线程:
指的是在程序中可以创建多个线程来执行不同的任务,Java语言是支持创建多线程
何时需要用多线程:
当需要同时执行多个任务时
多线程优点:
- 提升程序响应的速度
- 提升cpu利用率
- 改善代码结构(例如可以将大任务拆分称多个小任务
多线程的缺点:
- 线程越多,占用的内存越大(线程也是程序,程序需要占用内存)
- 多线程需要协调和管理,所以需要跟踪管理线程,使得cpu开销变大;
- 线程之间同时对共享资源的访问会相互影响,如果不加以控制会导致数据出错
线程同步
多线程同步:多个线程同时读到同一份共享资源时,可能会引发冲突。所以引入线程同步机制。
同步:排队+锁
- 几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作;
- 为了保证数据在方法中被访问时的正确性,在访问时加入锁机制
实例
/* 解决方法:
为核心的代码(出票,抢购,秒杀)进行加锁,只能一次一个线程对同步代码块(方法)进行访问
*/
public class TicktThread extends Thread{
static int n= 10;//票数
static Object object = new Object();
/*
synchronized修饰代码块
synchronized(同步锁){
}
同步锁:同步锁可以是Java中任意的类的对象,对象是唯一的;
此对象是记录有没有线程进入到同步代码块。
*/
// @Override
// public void run() {
// while (true){
// synchronized (object){
// if (n >0) {
// System.out.println(Thread.currentThread().getName()+"买到了"+n);
// n--;
// }else {
// break;
// }
// }
// }
// }
@Override
public void run() {
while (true){
print();
if (n <= 0) {
break;
}
}
}
/*
synchronized修饰的方法,方法位同步方法
这时同步锁对象就不需要我们自己提供了,会自己提供
当方法如果时非静态方法时锁对象是this
当方法如果是静态方法时,锁对象是类对象(类对象一个类只有一个)
*/
public static synchronized void print() {
if (n > 0) {
System.out.println(Thread.currentThread().getName() + "买到了" + n);
n--;
}
}
}
public class Test {
public static void main(String[] args) {
TicktThread thread = new TicktThread();
thread.setName("窗口1:");
TicktThread thread1 = new TicktThread();
thread1.setName("窗口2:");
thread1.start();
thread.start();
}
}
同步锁
- 确保一个时间点只有一个线程访问共享资源。
- 可以给共享资源加一把锁,哪个 线程获取了这把锁,才有权利访问该共享资源
特点:
同步锁可以是任何对象,必须唯一,保证多个线程获得是同一个对象(用来充当锁标记).
同步执行过程
- 第一个线程访问,锁定同步对象,执行其中代码.
- 第二个线程访问,发现同步对象被锁定,无法访问.
- 第一个线程访问完毕,解锁同步对象.
- 第二个线程访问,发现同步对象没有锁,然后锁定并访问
在Java代码中实现同步:
使用synchronized(同步锁)关键字同步方法或代码块。
synchronized (同步锁){ // 需要被同步的代码; }
synchronized还可以放在方法声明中,表示整个方法,为同步方法。
例如: public synchronized void show (String name){
/ 需要被同步的代码;
}
实例:
模拟卖票
两个窗口分别售票,票数为10张
public class Test {
public static void main(String[] args) {
TicktThread thread = new TicktThread();
thread.setName("窗口1:");
TicktThread thread1 = new TicktThread();
thread1.setName("窗口2:");
thread1.start();
thread.start();
}
}
public class TicktThread extends Thread{
static int n= 10;//票数
static Object object = new Object();
public void run() {
while (true){
synchronized (object){
if (n >0) {
System.out.println(Thread.currentThread().getName()+"买到了"+n);
n--;
}else {
break;
}
}
}
}
线程通信
线程通讯指的是多个线程通过相互牵制,相互调度,即线程间的相互作用。
实例1
package com.wyk.javathread.demo5;
import com.wyk.javathread.demo4.TicktThread;
public class Test {
public static void main(String[] args) {
TiicketTask task = new TiicketTask();
Thread thread = new Thread("窗口1");
Thread thread1 = new Thread("窗口2");
thread.start();
thread1.start();
}
}
package com.wyk.javathread.demo5;
public class TiicketTask implements Runnable{
Object object = new Object();
int n = 10;
// @Override
// public void run() {
// while (true){
// synchronized (object){//object,this
// if (n>0) {
// System.out.println(Thread.currentThread().getName()+"买到了"+n);
// n--;
// }else {
// break;
// }
// }
//
// }
//
// }
public synchronized void print(){
if (n>0) {
System.out.println(Thread.currentThread().getName()+"买到了"+n);
n--;
}
}
@Override
public void run() {
while (true){
this.print();
if (n<=0){
break;
}
}
}
}
- wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步锁对象。
- notify一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait, 就唤醒优先级高的那个。
- notifyAll一旦执行此方法,就会唤醒所有被wait的线程。
- 注意: .wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中
实例2
package com.wyk.javathread.demo6;
public class Test {
public static void main(String[] args) {
PrintNumTask task = new PrintNumTask();
Thread thread = new Thread(task, "线程1");
Thread thread1 = new Thread(task,"线程2");
thread.start();
thread1.start();
}
}
package com.wyk.javathread.demo6;
public class PrintNumTask implements Runnable{
int num = 0;
Object object= new Object() ;
/*
notify();wait();必须在同步代码块中进行
必须使用同步对象进行调用
*/
@Override
public void run() {
while (true){
synchronized (object){
object.notify();//唤醒外面等待的线程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (num <=100) {
System.out.println(Thread.currentThread().getName()+":"+(++num));
}else {
break;
}
try {
object.wait();//让线程等待
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
新增创建线程方式
实现Callable接口与使用Runnable相比,Callable功能更强大些.
- 相比run()方法,可以有返回值
- 方法可以抛出异常 • 支持泛型的返回值
- 需要借助FutureTask类,获取返回结果
接收任务
FutureTask futureTask = new FutureTask(任务);
创建线程
Thread t = new Thread(futureTask);
t.start();
Integer val = futureTask.get();获得线程call方法的返回