java多线程和解决线程同步问题

进程:线程离不开进程,先说一下什么是进程!(打开资源管理器,我们就能看到,当前运行的进程)。

线程:是进程中的单个顺序控制流,是一条执行路径。

单线程:一个进程如果只有一条执行路径,则成为单线程程序。

多线程:一个进程如果有多条执行路径,则成为多线程程序。

实现多线程

方式一:继承Thread类
1.定义一个类MyThread 继承Thread类
2.在MyThread类中重写Run()方法
3.创建对象
4.启动线程  用Start方法
public class MyThread extends Thread {
    @Override
    public void run() {
       for (int i=0;i<100;i++){
           System.out.println(i);

       }
    }
}

public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread m1=new MyThread();
        MyThread m2=new MyThread();
        m1.start();
        m2.start();
    }
}
方法2:实现Runnable接口
定义一个MyRunnable类,实现Runnable接口
在MyRunnable类中重写run方法
创建MyRunnable类的对象
创建Thread类对象,将MyRunnable对象作为构造方法的参数
启动线程

public class MyRunnable implements Runnable {
    
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}



public class MyRunnableDemo {
    public static void main(String[] args) {
        MyRunnable my=new MyRunnable();
        Thread t1=new Thread(my);
        Thread t2=new Thread(my);
        t1.start();
        t2.start();
    }

}

问题: 为什么要重写run()方法?

run方法是用来封装被线程执行的代码。

run()方法和start()方法的区别?

run():封装线程执行的代码,直接调用,相当于普通方法的调用。

start():启动线程,然后由JVM调用此线程的run()方法。

设置和获取线程名称

   public static void main(String[] args) {
        MyThread m1=new MyThread();
        m1.setName("王");
        String name = m1.getName();
        System.out.println(name);
    }

线程调度

 java中使用的是抢占式调度:优先级高的线程先使用CPU。优先级相同,会随机选一个。优先级高的线程获取的CPU时间片多一点。

        MyThread m1 = new MyThread();
        MyThread m2 = new MyThread();
        MyThread m3 = new MyThread();
//获取线程的优先级,优先级默认是5,最高是10,最小是1.
//        System.out.println(m1.getPriority());//5
//        System.out.println(m2.getPriority());//5
//        System.out.println(m3.getPriority());//5

//更改线程的优先级
        m1.setPriority(1);
        m2.setPriority(10);
        m3.setPriority(1);

线程控制

//Thread.sleep(); 使当前正在执行的线程停留,指定的秒数,然后继续执行。

//vodi join();等待这个线程死亡。
//下面例子,m1,结束后,m2,m3才运行。
        MyThread m1 = new MyThread();
        MyThread m2 = new MyThread();
        MyThread m3 = new MyThread();
 
        m1.setName("王");
        m2.setName("李");
        m3.setName("孙");
   m1.start();
        try {
            m1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        m2.start();
        m3.start();


//void setDaemon(boolean on) 将此线程标记为守护线程,运行的线程都是守护线程时,java虚拟机将退出。
//例子:当主线程刘备结束后,关羽和张飞也退出线程。

        MyThread m1 = new MyThread();
        MyThread m2 = new MyThread();
        
        m1.setName("关羽");
        m2.setName("张飞");
        Thread.currentThread().setName("刘备");
        m1.setDaemon(true);
        m2.setDaemon(true);
        m1.start();
        m2.start();
        for (int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }

线程生命周期

 线程同步 

案例:买票系统,3个窗体同时买票,然后用多线程。

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

public class SellTickerDmo {
    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();
    }
}

上面这样写会出问题,就是一张票,卖了好多次。我们需要的是,把操作共享数据的多条语句锁起来,就是加锁,同一时间,只能一个去访问。

同步代码块方法解决问题:

public class SellTicket  implements Runnable{
    private  int tickets=1000;
    private Object obj=new Object();
    @Override
    public void run() {
        while(true){
            //加锁
            synchronized (obj){
            if (tickets>0){
                try{
                    Thread.sleep(10);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
                tickets--;
            }
            }
        }
    }
}

Lock锁,解决同步问题: 

Lock是接口,不能直接实例化使用,可以使用它的实现类ReentrantLock。 

主要方法,获得锁 施放锁。

public class SellTicket  implements Runnable{
    private  int tickets=1000;
    private Lock lock =new ReentrantLock();
    @Override
    public void run() {
        while(true){
            try{
                lock.lock();
                if (tickets>0){
                    try{
                        Thread.sleep(10);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"zhang票");
                    tickets--;
                }
            }finally {
                lock.unlock();
            }
        }
    }
}

线程安全的类:

如果需要执行同步,并且保证线程安全可以使用下面的类。它们的底层方法都是用 synchronized 加锁的。

        StringBuffer sbf=new StringBuffer(); 
//下面这两个是线程安全的集合,但是我们一般不会去用。用下面的方法转!
        Vector ve=new Vector();
        Hashtable ht=new Hashtable();

//下面方法可以把集合转成 线程安全的。
List<String> list = Collections.synchronizedList(new ArrayList<String>());

猜你喜欢

转载自blog.csdn.net/weixin_44126152/article/details/106373872