javaAPI_多线程基础_多线程基础2


多线程基础2

1.多线程的实现方式2

(1).实现步骤
A:自定义类MyRunnable实现Runnable接口
B:重写run()方法
C:创建MyRunnable类的对象
D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

(2).代码实现:

//线程类代码
public class MyRunnable implements Runnable {

@Override
public void run() {
for (int x = 0; x < 100; x++) {
// 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
//测试类
public static void main(String[] args) {
// 创建MyRunnable类的对象
MyRunnable my = new MyRunnable();

//方法1
// 创建Thread类的对象,并把C步骤的对象作为构造参数传递
// Thread(Runnable target)
// Thread t1 = new Thread(my);
// Thread t2 = new Thread(my);
// t1.setName("林青霞");
// t2.setName("刘意");

//方法2
// Thread(Runnable target, String name)
Thread t1 = new Thread(my, "林青霞");
Thread t2 = new Thread(my, "刘意");

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


2.多线程实现的俩个方式的图解比较

 

3.多线程基本使用案例[*****]

(1).需求分析:
某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票


(2).实现方式1:使用继承Thread类来实现[测试代码,不可以使用]
//多线程类
public class SellTicket extends Thread {

// 定义100张票
// private int tickets = 100;
// 为了让多个线程对象共享这100张票,我们其实应该用静态修饰
private static int tickets = 100;

@Override
public void run() {
// 定义100张票
// 每个线程进来都会走这里,这样的话,每个线程对象相当于买的是自己的那100张票,这不合理,所以应该定义到外面
// int tickets = 100;

// 是为了模拟一直有票
while (true) {
if (tickets > 0) {
System.out.println(getName() + "正在出售第" + (tickets--) + "张票");
}
}
}
}

//使用测试类
public static void main(String[] args) {
// 创建三个线程对象
SellTicket st1 = new SellTicket();
SellTicket st2 = new SellTicket();
SellTicket st3 = new SellTicket();

// 给线程对象起名字
st1.setName("窗口1");
st2.setName("窗口2");
st3.setName("窗口3");

// 启动线程
st1.start();
st2.start();
st3.start();
}


(3)使用实现Runable接口的方式实现上述代码
//多线程类
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;

@Override
public void run() {
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (tickets--) + "张票");
}
}
}
}

//测试类
public static void main(String[] args) {
// 创建资源对象
SellTicket st = new SellTicket();

// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");

// 启动线程
t1.start();
t2.start();
t3.start();
}

(4).线程安全存在的问题
A:相同的票出现多次
CPU的一次操作必须是原子性的
B:还出现了负数的票
随机性和延迟导致的

注意:线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的

 

(5).线程安全的产生原因
A:首先想为什么出现问题?(也是我们判断线程是否有问题的标准)
是否是多线程环境
是否有共享数据
是否有多条语句操作共享数据(如,判断,输出,自增或自减)

B:如何解决多线程安全问题呢?
把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。


4.同步代码块

(1). 同步代码块格式
格式:
synchronized(对象){需要同步的代码;}

A:对象是什么呢?
我们可以随便创建一个对象试试。
B:需要同步的代码是哪些呢?
把多条语句操作共享数据的代码的部分给包起来

注意:[*****]
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
多个线程必须是同一把锁。


(2).代码实现[可用代码]

//多线程类
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;
//创建锁对象,公用的是一个锁对象才能够保证不出问题
private Object obj = new Object();

@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
//测试代码
public static void main(String[] args) {
// 创建资源对象
SellTicket st = new SellTicket();

// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");

// 启动线程
t1.start();
t2.start();
t3.start();
}


(3).同步的前提,好处,特点以及弊端
同步的前提
多个线程
多个线程使用的是同一个锁对象
同步的好处
同步的出现解决了多线程的安全问题。
同步的弊端
当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。


(4).同步代码块的锁以及同步方法的应用
A:同步代码块的锁对象是谁呢?[同步代码锁]
任意对象。

B:同步方法的格式及锁对象问题?[同步方法锁]
把同步关键字加在方法上。

同步方法是谁呢?
this

C:静态方法及锁对象问题?[静态方法锁]
静态方法的锁对象是谁呢?
类的字节码文件对象(也就是class文件,比静态还存在的就是class文件)。(反射会讲)


D:代码实现

//多线程类
public class SellTicket implements Runnable {

// 定义100张票
private static int tickets = 100;

// 定义同一把锁
private Object obj = new Object();
private Demo d = new Demo();

private int x = 0;

@Override
public void run() {
while (true) {
if(x%2==0){
synchronized (SellTicket.class) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}else {
sellTicket();

}
x++;
}
}

private static synchronized void sellTicket() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票 ");
}
}
}

class Demo {
}
//测试代码
public static void main(String[] args) {
// 创建资源对象
SellTicket st = new SellTicket();

// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");

// 启动线程
t1.start();
t2.start();
t3.start();
}

 

posted @ 2019-01-16 22:06  德墨特尔  阅读(126)  评论(0编辑  收藏  举报