精华内容
下载资源
问答
  • 答:多线程两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方面有两种,分别是synchronized,wait与notify
     
    

    答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口

    同步的实现方面有两种,分别是synchronized,wait与notify

    展开全文
  • Java的两种线程同步方法基本概念synchronizedLocksynchronized与Lock对比 基本概念 当多个线程同时操作一个可共享资源时会出现线程安全问题,将会导致数据不一致,因此使用同步锁来防止该操作执行完之前不许被其他...

    基本概念

    当多个线程同时操作一个可共享的资源时会出现线程安全问题,将会导致数据不一致,因此使用同步锁来防止该操作执行完之前不许被其他线程执行,从而保证了该变量的唯一性和准确性。使用synchronized和使用Lock是两种Java常用的实现线程同步方法。

    synchronized

    (1)介绍
    使用synchronized关键字,可以修饰普通方法、静态方法,以及语句块。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。需要注意的是调用静态方法时,锁住的不是对象,锁住的是类。

    //修饰普通方法
    public synchronized void function1(){ }
    
    //修饰语句块
    synchronized(object){ }
     
    //修饰静态方法
    public static synchronized int function2(){ }
    

    同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

    (2)同步方法示例代码
    这里以三个人同时买票为例,加上synchronized关键字,使买票的方法buy()成为同步方法,防止多个人抢到同一张票:

    public class TicketTest {
    	
    	public static void main(String[] args) {
    		BuyTicket buyTicket = new BuyTicket();
    		//同时启动三个线程买票
    		new Thread(buyTicket, "Jason").start();
    		new Thread(buyTicket, "Flash").start();
    		new Thread(buyTicket, "Lucy").start();
    	}
    }
    
    class BuyTicket implements Runnable {
    
    	private int ticketNum = 100;
    	boolean flag = true;//外部停止方式
    	@Override
    	public void run() {
    		while(flag) {
    			try {
    				buy();
    				Thread.sleep(10);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	//加上synchronized使buy()成为同步方法
    	private synchronized void buy() throws InterruptedException {
    		if(ticketNum <= 0) {
    			flag = false;
    			return;
    		}
    		Thread.sleep(10);
    		System.out.println(Thread.currentThread().getName()+"拿到第"+ticketNum--+"张票");
    	}
    }
    

    Lock

    (1)介绍

    • 从JDK5.0开始,Java提供了更强大的线程同步机制——通过显示定义同步锁对象来实现同步,同步锁使用Lock对象充当。
    • java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
    • ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显示加锁、释放锁。

    (2)示例代码
    这里定义了一把ReentrantLock,将加锁和解锁操作放在try语句中,保证解锁操作一定会执行。

    import java.util.concurrent.locks.ReentrantLock;//导入包
    
    public class TicketTest2 {
    	
    	public static void main(String[] args) {
    		BuyTicket2 buyTicket = new BuyTicket2();
    		new Thread(buyTicket, "Jason").start();
    		new Thread(buyTicket, "Flash").start();
    		new Thread(buyTicket, "Lucy").start();
    	}
    }
    
    class BuyTicket2 implements Runnable {
    
    	private int ticketNum = 100;
    	boolean flag = true;//外部停止方式
    	
    	private final ReentrantLock lock = new ReentrantLock();//定义lock锁
    	@Override
    	public void run() {
    		while(flag) {
    			try {
    				try {
    					lock.lock();//加锁
    					buy();
    				} finally{
    					lock.unlock();//解锁
    				}
    				
    				Thread.sleep(10);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	private void buy() throws InterruptedException {
    		if(ticketNum <= 0) {
    			flag = false;
    			return;
    		}
    		Thread.sleep(10);
    		System.out.println(Thread.currentThread().getName()+"拿到第"+ticketNum--+"张票");
    	}
    }
    

    synchronized与Lock对比

    • Lock是显示锁(手动开启和关闭锁),synchronized是隐式锁,出了作用域自动释放。
    • Lock只有代码块锁,synchronized有代码块锁和方法锁。
    • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好,并且具有更好的扩展性(提供更多的子类)。
    展开全文
  • 线程同步的两种方法实现 方式一: 同步代码块 方式一: 同步代码块 使用实现Runnable接口的方式 /** * 创建三个窗口,总票数为100张,使用实现Runnable接口的方式 * 存在线程安全问题,待解决。 * * 1. 卖票...

    线程的生命周期

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m7fOcMkO-1602074863111)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201007152149277.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPoXgflt-1602074863114)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201007154731960.png)]

    线程同步的两种方法实现

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9rgqicjj-1602074863117)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201007163933179.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t4ShQlyF-1602074863122)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201007180112778.png)]

    方式一: 同步代码块

    方式一: 同步代码块 使用实现Runnable接口的方式
    
    /**
     * 创建三个窗口,总票数为100张,使用实现Runnable接口的方式
     * 存在线程安全问题,待解决。
     *
     *  1. 卖票过程中,出现了重票、错票  --->线程安全问题
     *  2. 问题出现的原因: 当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也来操作车票。
     *  3. 如何解决: 当一个线程在操作ticket的时候,其他线程不能参与进来。直到线程A操作完ticket时
     *              其他线程才可以开始操作ticket。这种情况即是线程A出现了阻塞,也不能被改变。
     *  4. 在Java中,我们通过同步机制,来解决线程的安全问题。
     *
     *      方式一: 同步代码块
     *
     *          synchronized(同步监视器){
     *               //需要被同步的代码
     *
     *           }
     *          说明: 1. 操作共享数据的代码,即为需要被同步的代码  -->不能包含代码多了,也不能包含代码少了。
     *               2. 共享数据: 多个线程共同操作的变量。比如: ticket就是共享数据
     *               3. 同步监视器,俗称: 锁。任何一个类的对象,都可以充当锁。
     *                   要求: 多个线程必须要共用同一个把锁。
     *
     *                   补充: 在实现Runnable接口创建多线程的方式中,我们可以考虑,使用this充当同步监视器。
     *
     *
     *      方拾二: 同步方法
     *
     *  5. 同步的方式,解决了线程的安全问题。 --->好处
     *     操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。 --->局限性
     *
     * @author 阿昌
     * @create 2020-10-07 11:27
     */
    
    class WThread implements Runnable {
        private int ticket = 100;
        Object obj = new Object();
    
        @Override
        public void run() {
            while (true) {
                synchronized (this) {   //synchronized (obj) {
                    if (ticket > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                        System.out.println(Thread.currentThread().getName() + " 卖票,票号为: " + ticket);
                        ticket--;
                    } else {
                        break;
                    }
                }
    
            }
        }
    
        public static class WindowTest1 {
            public static void main(String[] args) {
                WThread wThread = new WThread();
    
                Thread t1 = new Thread(wThread);
                Thread t2 = new Thread(wThread);
                Thread t3 = new Thread(wThread);
    
                t1.setName("窗口1");
                t2.setName("窗口2");
                t3.setName("窗口3");
    
    
                t1.start();
                t2.start();
                t3.start();
    
    
            }
        }
    }
    
    方式一: 同步代码块 使用继承Thread类的方式实现
    
    /**例子:
     * 创建三个窗口,总票数为100张,使用继承Thread类的方式实现
     *
     * 存在线程安全问题,待解决。
     * ↓  ↓  ↓  ↓  ↓  ↓
     * 使用同步代码块来解决继承Thread类的方式的线程安全问题
     *
     * 说明: 在继承Thread类创建多线程的方式中,慎用this充当同步监视器。考虑使用当前类充当同步监视器。
     *
     * @author 阿昌
     * @create 2020-10-07 10:09
     */
    
    class Window extends Thread{
    
        private static int ticket = 100;
        static Object obj =new Object();
    
        @Override
        public void run() {
            while (true){
                //错误的方式: this代表的t1,t2,t3三个对象
                //synchronized(this){
                //正确的
    //          synchronized(obj){
                synchronized(Window.class){ //Class clazz = Window.class;Window.class只会加载一次
    
    
                if (ticket> 0){
    
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    System.out.println(getName() + ": 买票,票号为: "+ ticket);
                    ticket--;
                }else{
                    System.out.println(getName() + "票已售空");
                    break;
                }
                }
            }
        }
    }
    
    
    
    public class WindowTest {
        public static void main(String[] args) {
            Window w1 = new Window();
            Window w2 = new Window();
            Window w3 = new Window();
    
            w1.setName("窗口1");
            w2.setName("窗口2");
            w3.setName("窗口3");
    
            w1.start();
            w2.start();
            w3.start();
        }
    }
    

    方式二: 同步方法

    方式二: 同步方法 实现Runnable接口
    
    /**
     * 使用 同步方法 解决实现Runnable接口的线程安全问题
     *
     * 关于同步方法的总结:
     *  1. 同步方法仍然涉及到同步监视器,只是不需要我们显示的声明。
     *  2. 非静态的同步方法,同步监视器是: this
     *     静态的同步方法,同步监视器是: 当前类本身
     *  
     *
     * @author 阿昌
     * @create 2020-10-07 19:10
     */
    class WThread2 implements Runnable {
        private int ticket = 100;
        @Override
        public void run() {
            while (ticket > 0) {
    
                show();
            }
    
        }
    
        private synchronized void show(){// 同步监视器: this
            if (ticket > 0) {
    
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                System.out.println(Thread.currentThread().getName() + " 卖票,票号为: " + ticket);
                ticket--;
    
            }
        }
    }
    
    
        public class WindowTest2 {
            public static void main(String[] args) {
                WThread2 wThread2 = new WThread2();
    
                Thread t1 = new Thread(wThread2);
                Thread t2 = new Thread(wThread2);
                Thread t3 = new Thread(wThread2);
    
                t1.setName("窗口1");
                t2.setName("窗口2");
                t3.setName("窗口3");
    
    
                t1.start();
                t2.start();
                t3.start();
    
            }
        }
    
    方式二: 同步方法 继承Thread类
    
    /**
     * 使用 同步方法 来解决继承Thread类实现多线程安全问题
     * @author 阿昌
     * @create 2020-10-07 19:48
     */
    class Window3 extends Thread{
    
        private static int ticket = 100;
    
        @Override
        public void run() {
            while (true){
    
                show();
    
            }
        }
            private static synchronized void show(){//同步监视器: Window3.class
            //private  synchronized void show(){//同步监视器:this: w1,w2,w3。此种解决方法是错误的
                if (ticket> 0){
    
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": 买票,票号为: "+ ticket);
                    ticket--;
    
                }
            }
        }
    
    
    
    public class WindowTest3 {
        public static void main(String[] args) {
            Window3 w1 = new Window3();
            Window3 w2 = new Window3();
            Window3 w3 = new Window3();
    
            w1.setName("窗口1");
            w2.setName("窗口2");
            w3.setName("窗口3");
    
            w1.start();
            w2.start();
            w3.start();
        }
    }
    
    展开全文
  • 实现线程同步的种方法

    万次阅读 2018-09-27 09:50:52
    因此引入多线程同步,也就是说多个线程只能一个对共享资源进行更改,其他线程不能对数据进行修改。 如下一个个线程对一个银行账户进行存钱小实例,其中使用synchornized修饰方法实现线程同步 代码如下: `...
    • 在多线程程序中,会出现多个线程抢占一个资源的情况,这时间有可能会造成冲突,也就是一个线程可能还没来得及将更改的 资源保存,另一个线程的更改就开始了。可能造成数据不一致。因此引入多线程同步,也就是说多个线程只能一个对共享的资源进行更改,其他线程不能对数据进行修改。
    • 1.如下一个两个线程对一个银行账户进行存钱的小实例,其中使用synchornized修饰方法实现线程的同步
    • 代码如下:
    class bank{
    	private int count=100;
    	public synchronized void dispit() {
    		  count+=10;
    	}
    	public int getcount() {
    		return count;
    	}
    }
    class ThreadCount extends Thread{
    	private bank count;
    	private JTextArea textarea = new JTextArea();
    	public ThreadCount(bank count,JTextArea textarea) {
    		this.count = count;
    		this.textarea = textarea;
    	}
    	public void run() {
    		for(int i=0; i<10; i++) {
    			count.dispit();
    			textarea.append("账户余额为:"+count.getcount()+"\n");
    		}
    	}
    }
    

    2.同步是一种高开销的操作,因此应该尽量减少同步内容,因此也可以使用修饰代码块来代替修饰整个方法。

    class bank{
    	private int count=100;
    	public void dispit() {
    		synchronized(this) {
    		  count+=10;
    		}
    	}
    	public int getcount() {
    		return count;
    	}
    }
    class ThreadCount extends Thread{
    	private bank count;
    	private JTextArea textarea = new JTextArea();
    	public ThreadCount(bank count,JTextArea textarea) {
    		this.count = count;
    		this.textarea = textarea;
    	}
    	public void run() {
    		for(int i=0; i<10; i++) {
    			count.dispit();
    			textarea.append("账户余额为:"+count.getcount()+"\n");
    		}
    	}
    }
    

    3.使用volatile修饰数据,对于当下问题,只用使用volatile来修饰账户的余额变量即可。该修饰词是对域变量的访问提供了以这种防锁机制,相当于告诉虚拟机,该域的变量可能被更改。因此每次使用该域都要重新计算,而不是从寄存器中取出数据。从而实现线程的同步。该修饰词不能修改final类型变量

    class bank{
    	private volatile int count=100;
    	public void dispit() {
    		  count+=10;
    	}
    	public int getcount() {
    		return count;
    	}
    }
    class ThreadCount extends Thread{
    	private bank count;
    	private JTextArea textarea = new JTextArea();
    	public ThreadCount(bank count,JTextArea textarea) {
    		this.count = count;
    		this.textarea = textarea;
    	}
    	public void run() {
    		for(int i=0; i<10; i++) {
    			count.dispit();
    			textarea.append("账户余额为:"+count.getcount()+"\n");
    		}
    	}
    }
    

    4.使用重入锁实现线程同步。使用类ReentrantLock类来定义锁,其中lock()方法为打开锁,unlock()方法为关闭锁
    类似于synchronized修饰方法有一样功能。使用锁时间需要注意应该及时放开锁,不然会进入死锁状态。一般是在finally中释放锁

    class bank{
    	private volatile int count=100;
    	private Lock lock = new ReentrantLock();
    	public void dispit() {
    		 lock.lock();
    		 try {
    		  count+=10;
    		 }finally{
    			 lock.unlock();
    		 }
    	}
    	public int getcount() {
    		return count;
    	}
    }
    class ThreadCount extends Thread{
    	private bank count;
    	private JTextArea textarea = new JTextArea();
    	public ThreadCount(bank count,JTextArea textarea) {
    		this.count = count;
    		this.textarea = textarea;
    	}
    	public void run() {
    		for(int i=0; i<10; i++) {
    			count.dispit();
    			textarea.append("账户余额为:"+count.getcount()+"\n");
    		}
    	}
    }
    

    代码的输出结果如下:
    在这里插入图片描述
    可以看到,每次增加10 的时间只有一个线程在进行,也就是线程的同步

    5.使用ThreadLocal类来管理。不过该方法和同步机制不相同。该类管理的变量在每个线程中都有自己的副本,副本之间相互独立,因此获得的结果和其他不同。

    class bank{
    	private static ThreadLocal<Integer> count = new ThreadLocal() {
    	   protected Integer initialValue() {
    		   return 100;
    	   }
    	};
    	private Lock lock = new ReentrantLock();
    	public void dispit() {
    		 lock.lock();
    		 try {
    		  count.set(count.get()+10);
    		 }finally{
    			 lock.unlock();
    		 }
    	}
    	public int getcount() {
    		return count.get();
    	}
    }
    
    class ThreadCount extends Thread{
    	private bank count;
    	private JTextArea textarea = new JTextArea();
    	public ThreadCount(bank count,JTextArea textarea) {
    		this.count = count;
    		this.textarea = textarea;
    	}
    	public void run() {
    		for(int i=0; i<10; i++) {
    			count.dispit();
    			textarea.append("账户余额为:"+count.getcount()+"\n");
    		}
    	}
    }
    

    结果如图:
    在这里插入图片描述
    可以看到,在改程序中,好比两个账户相互独立,互不干扰一样。同样解决了相同的变量访问冲突问题。

    展开全文
  • 两种用法: synchronized方法: public synchronized void mutiThreadAccess(); synchronized代码块: synchronized(syncObject) { //访问syncObject代码 } 2、wait()方法和notify()方法 3、Lock lock(): 以...
  • Java线程同步是保证多线程状态下安全访问竞争资源编程手段,但线程同步在Java多线程编程中算是一个比较难难点,很多开发者甚至都不知道什么是竞争资源,也不知道时候需要进行线程同步,当然这是没有明确...
  •  同步两种方法实现,一种是利用synchronized标示,另外一种是加锁。  生成锁对象的方法是:private static Lock lock = new ReentrantLock();Lock是一个接口,而Reentrantlock是一个实现的类。构造方法有:...
  • 个人博客:小景哥哥 Java主要提供了3种实现同步机制: ​ ①synchronized关键字 ​ 在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在...synchronized关键字有两种用法,synchronized方法和synchro...
  • 线程同步的种实现方法

    千次阅读 2016-11-18 11:25:13
    二、为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象状态出现混乱,从而导致程序异常。举个例子,如果一个银行账户同时被个线程...
  • synchronized有两种用法(方法和代码块),还可用于静态方法,实例,类 synchronized方法 当一个方法体规模非常大时,使用同步方法会大大影响程序执行效率,所以Java提供了同步块。 synchronized块 synchronized
  • 线程两种实现方法:继承 Thread 类或者实现 Runnable 接口。 一.继承 Thread 类 //1、作为Thread子类,并重写run方法。把多线程的业务写在run方法中 //2、默认实现是super.run(); //3、创建线程对象 //4、开启...
  • 同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉...
  • 实现线程同步的方法

    2016-01-22 16:28:02
    同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉...
  • 线程两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方面有两种,分别是synchronized,wait与notify
  • 一、多线程的实现 1、 继承 Thread 类 启动线程步骤: a、定义Thread类的子类(继承Thread类),并重写该类的run()方法,该方法方法体就是线程需要完成的任务,run()方法也称为线程执行体 b、创建Thread子类的...
  • 1)实现线程两种方法: 继承 Thread 类或者实现 Runnable 接口 2) 实现同步也有两种,一种是用同步方法,一种是用同步块… 同步方法就是在 方法返回类型后面加上 synchronized, 比如: public void synchronized add...
  • 两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 下文用三种不同的方式实现...
  • 同步的实现方面有两种,分别是synchronized,wait与notify  wait():使一个线程处于等待状态,并且释放所持有的对象的lock。  sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉...
  • 在典型卖票程序中,需要考虑多个窗口买票时数据同步问题,对此可能需要线程同步,下面简单介绍下两种同步方法; Demo:public static void main(String[] args) { ThickesRunnable tr = new ThickesRunnable()...
  • Java线程原理和5种同步方法自己开发了一个股票智能分析软件,功能很强大,需要点击下面链接获取:目录1 Java线程原理和两种实现方式... 11.1 java线程原理和源码解析... 11.2 实现 Runnable 接口实现run方法... ...
  • 同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉...
  • 同步的实现方面有两种,分别是synchronized,wait与notify wait():使一个线程处于等待状态,并且释放所持有的对象的lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉...
  • 线程两种实现方法:  方法一:继承Thread类,重写方法run();  方法二:实现Runnable接口,实现方法run(); 同步两种方法:  方法一:用同步方法(在方法返回类型后面加上synchronized);  方法二:用...
  • Java多线程实现的方式有四种 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法实现Runnable...前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式返回值是void,所以没有...
  • 为了确保在任何时间点一个共享资源只能被一个线程使用,使用了“同步”。 一、使用同步方法 package sort; public class Timer { private static int num=0; public synchronized void add(String name){ num+...
  • 同步的实现方法有五:1.同步方法;2.同步代码块;3.使用特殊域变量(volatile)实现线程同步;4.使用重入锁实现线程同步;5.使用局部变量实现线程同步 。其中多线程实现过程中需注意重写或者覆盖run()方法,而对于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,899
精华内容 759
关键字:

两种线程同步的实现方法