创建多线程两种方式参考例子(synchronized)
作者:互联网
线程窗口买票例子(存在线程安全问题)
开发中:优先选择Runnable接口的方式
原因:
1
.实现的方式没有类的单继承性的局限性
2
.实现的方式更适合来处理多个线程有共享数据的情况
二者联系:
public
class
Thread
implements
Runnable
相同点:两种都要重写run(),将线程要执行的逻辑声明再run()中。
创建线程的两种方式选择
方式一:继承Thread类
public class WindowsTest { public static void main(String[] args) { // 方式一:继承于Thread类测试 Window1 w1 = new Window1(); Window1 w2 = new Window1(); Window1 w3 = new Window1(); w1.setName("窗口一"); w2.setName("窗口二"); w3.setName("窗口三"); w1.start(); w2.start(); w3.start(); } } class Window1 extends Thread { // 使用了static修饰多个线程调用也是只有100张票 private static int ticket = 100; // 重写run()方法 @Override public void run() { while (true) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket); ticket--; }else { break; } } } }
方式二:实现Runaable接口
public class WindowsTest { public static void main(String[] args) { // 方式二:实现Runnable接口测试 Window w = new Window(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); t1.start(); t2.start(); t3.start(); } } class Window implements Runnable { private int ticket = 100; // 重写run()方法 @Override public void run() { while (true) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket); ticket--; }else { break; } } } }
以下解决线程安全问题
方式一:同步代码块
说明:
1
.操作共享数据代码,即为需要被同步的代码
2
.共享数据:多个线程共同操作的变量。比如:ticket就是共享数据
3
.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。
(
要求:多个线程必须公用同一把锁。)
继承方式:
public class WindowsTest { public static void main(String[] args) { // 方式一:继承于Thread类测试 Windows w1 = new Windows(); Windows w2 = new Windows(); Windows w3 = new Windows();
// 此时创建了多个对象执行 w1.setName("窗口1"); w2.setName("窗口2"); w3.setName("窗口3"); w1.start(); w2.start(); w3.start(); } } class Windows extends Thread { // 使用了static修饰多个线程调用也是只有100张票 private static int ticket = 100; // 这里需要static来保证锁的唯一性(调用时可能创建了多个对象调用) @Override public void run() { while (true) { synchronized (Windows.class) { if (ticket > 0) {
// 延时 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket); ticket--; }else { break; } } } } }
实现方式:
public class WindowsTest { public static void main(String[] args) { // 方式二:实现Runnable接口 Windows w = new Windows();
// 这边共用了一个对象 Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); t1.start(); t2.start(); t3.start(); } } class Windows implements Runnable { private int ticket = 100; @Override public void run() { while (true) { synchronized (windows.class) { if (ticket > 0) {
// 延时 try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket); ticket--; }else { break; } } } } }
方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。
继承方式:
// 继承于Thread类 public class WindowsTest { public static void main(String[] args) { Windows w1 = new Windows(); Windows w2 = new Windows(); Windows w3 = new Windows(); w1.setName("窗口一"); w2.setName("窗口二"); w3.setName("窗口三"); w1.start(); w2.start(); w3.start(); } } class Windows extends Thread{ private static int ticket = 100; @Override public void run() { while (true) {
// 调用方法 show(); } } // 创建一个方法,将共享数据声明在里方法里 private static synchronized void show() { // private synchronized void show() //同步监视器 w1,w2,w3 if (ticket > 0) { try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket); ticket--; } } }
实现方式:
// 实现Runnable接口 public class WindowsTest1 { public static void main(String[] args) { Windows w = new Windows(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); t1.start(); t2.start(); t3.start(); } } class Windows implements Runnable{ private int ticket = 100; @Override public void run() { while (true) {
// 调用方法 show(); } } // 同步监视器this private synchronized void show() { if (ticket > 0) { try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket); ticket--; } } }
线程安全举例:
把厕所比作成共享数据(如以上的ticket),A进去上厕所了还没上完B就也进去上厕所了所以就出现了安全问题,
解决方法就是在厕所上一把锁等A上完厕所之后B才能进去上厕所,即使A进入后睡了一觉(sleep)也要等A出来
后B才能进入,从而解决了安全问题。
标签:synchronized,Thread,参考,Windows,start,new,ticket,多线程,public 来源: https://www.cnblogs.com/lxh-daniel/p/16672220.html