多进程和synchronized关键字

多线程

多线程有三种实现方法:
1、继承Thread类

重写run()方法。然后直接new这个对象的实例,创建一个线程的实例,再调用start()方法启动线程。(其实本质上Thread是实现了Runnable接口的一个实例,Thread源文件:public class Thread implements Runnable)

public class Demo extends Thread{//定义一个类继承Thread类。
	private int count = 10;
	@Override//重写Thread类中的run方法。
	public void run() {
		while(true) {
			System.out.print(count+" ");
			if(--count == 0) {
				return;
			}
		}
	}
	public static void main(String[] args) {
        //创建一个线程的实例(Thread类的子类对象)
        //调用start方法启动线程执行run方法
		new Demo().start();
	}
}
//执行结果:10 9 8 7 6 5 4 3 2 1 

/*==============================源码=======================================*/
public
class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
2、实现Runnable接口

重写run()方法。然后调用new Thread(runnable)的方式创建一个线程,再调用start()方法启动线程。

public class Demo implements Runnable{//定义类实现Runnable接口。
	private int count = 0;
	@Override//重写接口中的run()方法,将线程的任务代码封装到run()方法中。
	public void run() {
		while(true) {
			System.out.print(count+" ");
			if(++count == 10) {
				return;
			}
		}
	}
	public static void main(String[] args) {
		//通过Thread类创建线程对象,并将Runnable接口的子类对象
        //作为Thread类的构造函数的参数进行传递。
        new Thread(new Demo()).start();
	}
}
//执行结果:0 1 2 3 4 5 6 7 8 9 
3、实现Callable接口

重写call()方法。Callable是类似于Runnable的接口,是属于Executor框架中的功能类。是JDK1.5中引入的新特性。

public class Demo implements Callable<Integer>{
	@Override
	public Integer call() throws Exception {		
		for(int i =0; i<10;i++) {
			System.out.print(i+" ");
			Thread.sleep(100);
		}
		System.out.println();
		System.out.println(Thread.currentThread().getName()+"线程执行结束");
		return 100;
	}
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Callable<Integer> callable =new Demo();
		FutureTask<Integer> task = new FutureTask<>(callable);
		new Thread(task).start();
		Integer num = task.get();
		System.out.println("返回值为"+ num);	
		for(int i =0; i<10;i++) {
			System.out.print(i+" ");
			Thread.sleep(100);
		}
		System.out.println();
		System.out.println(Thread.currentThread().getName()+"线程执行结束");
	}
}
/*运行结果:	 0 1 2 3 4 5 6 7 8 9 
		    Thread-0线程执行结束
			返回值为100
			0 1 2 3 4 5 6 7 8 9 
            main线程执行结束
*/
Runnable和Callable的不同点:

①Callable规定的方法是call(),而Runnable规定的方法是run().

②Callable的任务执行后可返回值,而Runnable的任务是不能返回值的(有返回值用callable方法,无返回值用runnable方法)

③call()方法可抛出异常,而run()方法是不能抛出异常的。

④运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果.通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果

实现Runnable接口的好处,优点

1、实现Runnable接口的方法中线程类只是实现了Runnable接口,还可以继承其他的类。避免的java单继承的局限性。

2、在这种方式下,可以多个线程共享一个Runnable对象,利于资源共享。适合多个相同的线程去处理同一份资源。

尽量使用实现Runnable接口的方法

synchronized关键字

synchronized 有三种方式来加锁,分别是
1.修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
2.静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
3.修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

synchronized原理

线程在获取锁的时候,实际上就是获得一个监视器对象(monitor) ,monitor 可以认为是一个同步对象,所有的Java 对象是天生携带 monitor。而monitor是添加Synchronized关键字之后独有的。synchronized同步块使用了monitorenter和monitorexit指令实现同步,这两个指令,本质上都是对一个对象的监视器(monitor)进行获取,这个过程是排他的,也就是说同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。
线程执行到monitorenter指令时,会尝试获取对象所对应的monitor所有权,也就是尝试获取对象的锁,而执行monitorexit,就是释放monitor的所有权。

显式锁和隐式锁

Synchronizaed:Java中的关键字,是由JVM来维护的。是JVM层面的锁。
Lock:是JDK5以后才出现的具体的类。使用lock是调用对应的API。是API层面的锁
区别:
sync是底层是通过monitorenter进行加锁(底层是通过monitor对象来完成的,其中的wait/notify等方法也是依赖于monitor对象的。只有在同步块或者是同步方法中才可以调用wait/notify等方法的。因为只有在同步块或者是同步方法中,JVM才会调用monitory对象的);通过monitorexit来退出锁的。而lock是通过调用对应的API方法来获取锁和释放锁的
Sync是隐式锁。Lock是显示锁
所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁的操作。
在使用sync关键字的时候,不用写其他的代码,然后程序就能够获取锁和释放锁了。那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话话,是不会出现死锁的。
在使用lock的时候需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。手动获取锁方法:lock.lock()。释放锁:unlock方法。需要配合tyr/finaly语句块来完成。

隐式锁
package practice;

public class ThreadTest implements Runnable {
    private String text;
    private Object prev;
    private Object self;

    public ThreadTest(String text, Object prev, Object self) {
        this.text = text;
        this.prev = prev;
        this.self = self;
    }

    @Override
    public void run() {
        int i = 0;
        while (++i <= 10) {
            synchronized (prev) {
                synchronized (self) {
                    System.out.println(Thread.currentThread().getName() + ": " + text);
                    self.notify();//唤醒其他线程竞争self锁
                }
                try {
                	prev.wait();//prev锁释放,当前线程休眠
                	//jvm会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("done");
    }

    public static void main(String[] args) throws InterruptedException {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
        ThreadTest threadA = new ThreadTest("A", c, a);//打印结束,按顺序释放a,c锁
        ThreadTest threadB = new ThreadTest("B", a, b);//拿到锁a,申请锁b,结束后按顺序释放b,c锁
        ThreadTest threadC = new ThreadTest("C", b, c);//拿到锁b,再申请锁c,结束后释放b,c
        Thread A = new Thread(threadA);
        A.setName("线程A");
        A.start();
        Thread.sleep(100);//保证按ABC顺序来
        Thread B = new Thread(threadB);
        B.setName("线程B");
        B.start();
        Thread.sleep(100);
        Thread C = new Thread(threadC);
        C.setName("线程C");
        C.start();
        Thread.sleep(3000);
    }
}
显式锁
public class LockTest {
	public static void main(String[] args) throws InterruptedException {
		MyThread m = new MyThread();
		Thread A = new Thread(m);
		A.setName("线程A");
		A.start();
		Thread.sleep(20);//确保线程A先执行
		Thread B = new Thread(m);
		B.setName("线程B");
		B.start();
		Thread.sleep(10);//确保B在C前面执行
		Thread C = new Thread(m);
		C.setName("线程C");
		C.start();
	}
}
class MyThread implements Runnable {
	private int i = 30;
	Lock l = new ReentrantLock(true);
	@Override
	public void run() {
		while (true) {
			l.lock();//上锁
			if (i == 0) {
				break;
			}
			if (i % 3 == 0) {
				System.out.println(Thread.currentThread().getName() + ":   A");
				i--;
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else if (i % 3 == 2) {
				System.out.println(Thread.currentThread().getName() + ":   B");
				i--;
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else if (i % 3 == 1) {
				System.out.println(Thread.currentThread().getName() + ":   C");
				i--;
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			l.unlock();//解锁
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值