java-多线程

啥是线程

线程是程序执行的最小单位,一个进程可以有多个线程

线程都有哪些状态

创建(new)------>运行(runable)------->等待(wating)------->阻塞(blocked)------>结束(terminated)
创建:创建后尚未启动的线程处于的状态
运行:runable包括了线程状态的running和ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待cpu分配执行时间。
等待:处于这种状态的线程不会被分配cpu执行时间。等待状态又被分为无限期等待和有限期等待。处于无限期等待的线程需要被其他线程显示地唤醒(没有设置tiemout参数的Object.wait()、没有设置timeout的Thread.join()方法都会进入无限期等待);有限期等待状态无需被其他线程显示的唤醒,在一定时间后它们会由系统自动唤醒(Thread.sleep(),这是了timeout参数的Object.wait()、设置了timeout的Thread.join()方法都会进入有限期等待)
结束:已终止线程的线程状态,线程已经结束执行

如何创建线程

1-继承Thread类

public class TestThread{
	public static void main(String[] args){
		MyThread myThread = new MyThread();
		myThread.start();
	}
}

class MyThread extends Thread{
	@Override
	public void run(){
		-----方法体
	}
}

2-实现Runnable接口

public class TestThread{
	public static void main(String[] args){
		Thread thread = new Thread(new MyThread());
		thread.start();
	}
}

class MyThread implements Runnable{
	@Override
	public void run(){
		----方法体
	}
}

3-实现Callable接口

public class CallableTest {
 
    public static void main(String[] args) {
        //执行Callable 方式,需要FutureTask 实现实现,用于接收运算结果
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
        new Thread(futureTask).start();
        //接收线程运算后的结果
        try {
            Integer sum = futureTask.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
 
class MyCallable implements Callable<Integer> {
 
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }
}

4-线程池

public class ThreadPoolExecutorTest {
 
    public static void main(String[] args) {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPool threadPool = new ThreadPool();
        for(int i =0;i<5;i++){
            //为线程池分配任务
            executorService.submit(threadPool);
        }
        //关闭线程池
        executorService.shutdown();
    }
}
 
class ThreadPool implements Runnable {
 
    @Override
    public void run() {
        for(int i = 0 ;i<10;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }

}

啥是线程同步

线程同步的真实意思其实和字面意思是恰恰相反的。线程同步的真实意思是“排队”:几个线程制键要排队,一个一个对共享资源进行操作,而不是同时进行操作。
因此关于线程同步,其实就是线程排队。同步就是排队。线程同步的目的就是为了避免线程“同步”执行。
同步:我做完你再做。当一个线程访问该资源时,不允许其他线程访问
异步:我做我的你做你的。当一个线程可以同时访问一个资源,可能会发生线程安全问题。

为啥要线程同步

由于多个线程可能同时操作同一个数据,就好比买票,多个人可能会同时争抢一张票的情况,如果不进行线程同步,那么就会出现线程安全的问题。

线程同步的方法

线程有4中同步方法,分别为wait()、sleep()、notify()和notifyAll()。

wait():使线程处于一种等待状态,释放所持有的对象锁。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用它时要捕获InterruptedException异常,不释放对象锁。

notify():唤醒一个正在等待状态的线程。注意调用此方法时,并不能确切知道唤醒的是哪一个等待状态的线程,是由JVM来决定唤醒哪个线程,不是由线程优先级决定的。

notifyAll():唤醒所有等待状态的线程,注意并不是给所有唤醒线程一个对象锁,而是让它们竞争。

如何才能线程同步

前面已经说了为什么要线程同步,下面我们来研究一下怎么才能实现线程同步。
当我们出现多个线程同时访问一个共享资源的时候,我们可以给共享资源加一个锁,这把锁只有一把钥匙。哪个线程获得了这把钥匙,才有权力访问该共享资源。这个锁就是线程同步锁。此时我们会想到我们该把锁加在什么位置?
当然是加在共享资源上了。这可能是我们脑海中首先冒出的想法。没错,如果有可能,我们当然尽量把同步锁加在共享资源上,一些比较完善的共享资源,比如文件系统,数据库系统等,自身都提供了比较完善的同步锁机制。我们不用另外给这些资源加锁,这些资源自己就有锁。
所以我们应该将锁加在访问共享资源的代码片段上。其次我们要考虑加一个什么样的锁。
这里我们需要注意的是:访问同一个共享资源的不同代码片段,应该加上同一个同步锁;如果加的是不同的同步锁,那么便没有任何意义。因此同步锁本身也一定是多个线程之间的共享对象。

synchronized同步锁

synchronized关键字,它可以保证在同一时刻最多只有一个线程执行该段代码。
synchronized有三种应用方式:
1-普通同步方法(实例方法),锁是当前实例对象,进入同步代码块前要获得当前实例的锁。

public class synchronizedTest implements Runnable {
    //共享资源
    static int i =0;
    /**
     * synchronized 修饰实例方法
     */
    public synchronized void increase(){
        i++;
    }
    @Override
    public void run(){
        for (int j =0 ; j<10000;j++){
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        synchronizedTest test = new synchronizedTest();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

2-静态同步方法,锁是当前类的class对象,进入同步代码前要获得当前类对象的锁

public class synchronizedTest implements Runnable {
    //共享资源
    static int i =0;
    /**
     * synchronized 修饰实例方法
     */
    public static synchronized void increase(){
        i++;
    }
    @Override
    public void run(){
        for (int j =0 ; j<10000;j++){
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new synchronizedTest());
        Thread t2 = new Thread(new synchronizedTest());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }

3-同步方法块,琐是括号里面的对象,对给定对象加锁,进入同步代码块前要获得给定对象的锁

 public class synchronizedTest implements Runnable {
    static synchronizedTest instance=new synchronizedTest();
    static int i=0;
    @Override
    public void run() {
        //省略其他耗时操作....
        //使用同步代码块对变量i进行同步操作,锁对象为instance
        synchronized(instance){
            for(int j=0;j<10000;j++){
                i++;
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值