美文网首页
Java多线程之线程安全与同步实例

Java多线程之线程安全与同步实例

作者: 征程_Journey | 来源:发表于2017-05-21 11:27 被阅读0次

1.1    线程安全与同步实例

1.1.1  购票同步对象锁

/*

* 用程序模拟铁路售票系统:实现通过两个售票点发售某日某次列车的50张车票,

* 一个售票点用一个线程表示

*/

publicclass SyncDemo {

public static void main(String[] args) {

/*

* new SaleTicketThread("窗口1").start(); new

* SaleTicketThread("窗口2").start();

*/

// 创建票对象(内部封装了卖票的方法,并且具备运行在线程中的能力)

Ticket tickt = new Ticket();

// 让多个窗口同时卖票(让线程执行指定的任务对象)

new Thread(tickt, "窗口1").start();

new Thread(tickt, "窗口2").start();

}

}

classTicket implements Runnable {

int num = 50;// 票数

Object obj = new Object();

@Override

public void run() {

// 不停地卖票

while (true) {

sale();

}

}

/**

* 卖票,每调用一次,卖一张票

*/

//同步方法,其实就是同步代码块的简写方式

public synchronized void sale() {

// 同步代码块,同一时间只能有一个线程进行执行里面的代码

//               synchronized (this) {// 同步锁,每个对象都可以作为同步锁进行使用(可用任何对象)

if (num > 0) {

try {

Thread.sleep(100);

System.out.println(Thread.currentThread().getName()

+"...sale..." + num--);

} catch(InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

}

//               }

}

}

classSaleTicketThread extends Thread {

private int num = 50;

public SaleTicketThread(String name) {

super(name);

}

@Override

public void run() {

while (num > 0) {

System.out.println(getName()+ "......sale....." + num);

num--;

}

}

}

1.1.2  同账户同步存钱

publicclass Ex1 {

public static void main(String[] args){

Account account = newAccount();

new Thread(account, "小强").start();

new Thread(account, "小花").start();

}

}

classAccount implements Runnable{

private int money = 0;  //存款

@Override

public void run() {

//存钱三次,每次存100元,并且在读完之后显示账户的余额

for(int i=0;i<3;i++){

saveMoney(100);

}

}

/**

* 存钱

*/

public synchronized void saveMoney(intmoney){

this.money +=money;

System.out.println(Thread.currentThread().getName()+"存入100元,账户余额为"+this.money);

try {

Thread.sleep(500);

} catch (InterruptedExceptione) {

// TODOAuto-generated catch block

e.printStackTrace();

}

}

}

1.1.3  火车过山洞

/*

* 有5辆火车要过山洞,但确保山洞同时只能有一辆火车通过(过山洞需要1秒),打印输出火车通过的顺序。

* (过山洞的顺序是不可控的,只要保证同一时间只有一辆火车能通过山洞即可)

* 提示:使用线程同步,一辆火车就是一个线程

*/

publicclass Ex2 {

public static void main(String[] args){

new Train("火车1").start();

new Train("火车2").start();

new Train("火车3").start();

new Train("火车4").start();

new Train("火车5").start();

}

}

classTrain extends Thread{

public Train(String name){

super(name);

}

@Override

public void run() {

synchronized (Train.class) {

System.out.println(getName()+"过山洞.....");

try {

Thread.sleep(1000);

} catch(InterruptedException e) {

// TODOAuto-generated catch block

e.printStackTrace();

}

}

}

}

1.1.4  处理单例模式中的线程同步问题

在懒汉式单例模式中存在线程同步问题

处理方案:采用双重判断的形式同时解决效率和线程安全的问题

publicclass Demo {

public static void main(String[] args){

new Thread() {

@Override

public void run() {

System.out.println(Singleton3.getInstance());

}

}.start();

new Thread() {

@Override

public void run() {

System.out.println(Singleton3.getInstance());

}

}.start();

}

}

// 单例模式(饿汉式)

classSingleton {

//静态字段是在类加载的时候就初始化了

private static Singleton instance = newSingleton();

// 私有化构造方法,防止外界创建对象

private Singleton() {

}

public static Singleton getInstance() {

return instance;

}

}

// 单例模式(懒汉式)

// 存在线程安全问题,可以通过双重判断加同步处理解决这里的线程安全问题

classSingleton2 {

private static Singleton2 instance;

private Singleton2() {

// emty

}

// 在这里,线程安全问题只会出现在第一次创建对象的时候,只要对象已经被创建完,

// 那么就不需要再对代码进行同步处理

// public static synchronizedSingleton2 getInstance(){//存在线程安全问题,可以通过双重判断加同步处理解决这里的线程安全问题

public static Singleton2 getInstance(){

if (instance == null) {        //通过双重判断对象是否存在

synchronized(Singleton2.class) {//同步

if(instance == null) {

try{

Thread.sleep(100);

}catch (InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

instance= new Singleton2();

}

}

}

return instance;

}

}

/*使用静态内部类实现单例模式

* 在类加载的时候会加载类中的成员,会初始化静态字段,将类中的成员加载到内存中(方法区)

*

*/

classSingleton3{

private Singleton3(){

}

//静态代码块只会在类加载的时候被调用一次

static{

System.out.println("外部类中的静态代码块......");

}

//静态内部类

private static class Inner{

static Singleton3 instance =new Singleton3();

static{

System.out.println("内部类中的静态代码块.....");

}

}

public static Singleton3 getInstance(){

return Inner.instance;

}

}

1.1.5  数字和字母的间隔输出

/**

* 1.         写两个线程,一个线程打印 1~52,另一个线程打印字母A-Z打印顺序为12A34B56C……5152Z(2个数字1个字母)。

提示:使用线程间的通信。

*/

publicclass Ex1 {

public static void main(String[] args){

// TODO Auto-generated methodstub

Printer printer = newPrinter();

newNumberThread(printer).start();

newLetterThread(printer).start();

}

}

//数字输出线程

classNumberThread extends Thread{

private Printer printer;

public NumberThread(Printer printer){

this.printer = printer;

}

@Override

public void run() {

for(int i=1;i<=52;i++){

printer.printNum(i);

}

}

}

//字母输出线程

classLetterThread extends Thread{

private Printer printer;

public LetterThread(Printer printer){

this.printer = printer;

}

@Override

public void run() {

for(charc='A';c<='Z';c++){

printer.printLetter(c);

}

}

}

/**

* 打印输出类

*/

classPrinter{

private boolean numOut = false;  //信号量,记录数字是否已经输出

//输出数字

public synchronized void printNum(intnum){

try {

if(numOut){//如果数字已经输出,就等待输出字母

wait();//注意:wait、notify的调用者必须是当前同步代码块对应的同步锁

}

System.out.println(num);  //输出数字

//如果刚刚输出的数字是偶数的话,就唤醒字母输出线程

if(num % 2 == 0){

numOut =true;  //标记已经输出数字

notify();       //唤醒字母输出线程去输出字母

}

Thread.sleep(200);

} catch (InterruptedExceptione) {

// TODOAuto-generated catch block

e.printStackTrace();

}

}

//输出字母

public synchronized voidprintLetter(char c){

try {

if(!numOut){    //如果还没有输出数字,就等待数字输出

wait();

}

System.out.println(c);   //输出字母

numOut = false;       //标记已经输出国字母,等待输出数字

notify();             //唤醒数字输出线程去输出数字

Thread.sleep(200);

} catch (InterruptedExceptione) {

// TODOAuto-generated catch block

e.printStackTrace();

}

}

}

1.1.6  主子线程的循环输出

/**

* 子线程循环3次,接着主线程循环6次,接着又回到子线程循环3次,接着再回到主线程又循环6次,如此循环10次,请写出程序

*/

publicclass Ex2 {

static boolean flag = false; // 记录子线程是否已经输出

static Object lock = new Object();

public static void main(String[] args){

// TODO Auto-generated methodstub

// 子线程

new Thread() {

@Override

public void run() {

try {

for(int i = 1; i <= 10; i++) {

synchronized(lock) {

if(flag) {

lock.wait();

}

System.out.println("~~~~~~~~~~~~~~第" + i

+"回合~~~~~~~~");

for(int j = 1; j <= 3; j++) {

System.out.println("子线程" + j);

Thread.sleep(200);

}

flag= true;

lock.notify();

}

}

} catch(InterruptedException e) {

//TODO Auto-generated catch block

e.printStackTrace();

}

};

}.start();

// 主线程

for (int i = 1; i <= 10;i++) {

try {

synchronized(lock) {

if(!flag){

lock.wait();

}

for(int j = 1; j <= 6; j++) {

System.out.println("主线程....." + j);

Thread.sleep(200);

}

flag= false;

lock.notify();

}

} catch(InterruptedException e) {

// TODOAuto-generated catch block

e.printStackTrace();

}

}

}

}

相关文章

  • Java多线程之线程安全与同步实例

    1.1 线程安全与同步实例 1.1.1 购票同步对象锁 【 /* * 用程序模拟铁路售票系统:实现通过两个售票点...

  • Java并发之synchronized

    Java多线程同步关键词是常用的多线程同步手段。它可以修饰静态类方法,实例方法,或代码块。修饰static静态方法...

  • 5月份第一周学习安排

    学习内容: java多线程及线程同步的方法(使用) java多线程各种同步方法的原理和优缺点 java多线程设计模...

  • Java之同步代码块

    Java多线程的同步代码块 synchronized(对象){ 需要同步的代码 } 同步代码块可以解决安全...

  • Android中的多线程

    1. Java多线程基础 Java多线程,线程同步,线程通讯 2. Android常用线程 HandlerThre...

  • java多线程--线程安全与同步

    1、什么是线程安全?我们通常会说HashMap 和HashTable的区别是一个是线程不安全的,一个是线程安全的。...

  • 7.5java线程深度解析:线程的同步

    线程的同步是保证多线程安全访问竞争资源的一种手段。线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞...

  • Java 线程安全

    参考《深入了解Java虚拟机,JVM高级特性与最佳实践》 线程安全的实现方法 互斥同步: 指再多线程访问贡献数据...

  • 多线程--同步与锁

    同步与锁 上一篇中,笔者介绍了Java多线程的基础知识,主要讲解了进程/线程的区别、Java多线程的创建、Java...

  • 第十六章、synchronized和ReentrantLock

    Java在编写多线程程序时,为了保证线程安全,需要对数据同步,经常用到两种同步方式就是Synchronized和重...

网友评论

      本文标题: Java多线程之线程安全与同步实例

      本文链接:https://www.haomeiwen.com/subject/nkbmxxtx.html