java创建线程两种方式参考例子(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才能进入,从而解决了安全问题。
posted @ 2022-09-09 14:22  lai_xinghai  阅读(131)  评论(0)    收藏  举报