Synchronized和Lock的区别是什么?
1.synchronized是Java中的关键字,是jdk自带的;Lock是一个接口
2.synchronized在线程执行发生异常时,jvm会让线程释放锁,因此不会导致死锁现象发生;Lock在finally中必须通过unLock()去释放锁,不然容易造成线程死锁
3.使用synchronized时,如果A线程阻塞,B线程会一直等待,不能够响应中断;Lock可以尝试获得锁,线程可以不用一直等待,通过interrupt()方法能够响应中断(interrupt无法中断已经获取的锁,只能中断等待状态)
4.synchronized无法判断锁的状态;Lock可以知道有没有成功获取锁(可以通过其中的tryLock()等自带的多个方法去尝试获取锁)在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当多线程竞争资源非常激烈时,此时Lock的性能要远远优于synchronized。具体使用时要根据适当情况选择。
案例一
方法一 继承Thread类
package sell;
import java.lang.Thread;
public class SaleSysTest {
public static void main(String[] args) {
//创建5个线程,传入线程名[001]、[002]...并开启
for(int i=1;i<6;i++) {
new SaleThread("[00"+i+"]").start();
}
}
}
class SaleThread extends Thread{
//车票数被共享,所以定义为static,数量为50.
private static int ticket=50;
//通过锁来保证线程不会重复访问
private static Object obj=new Object();
//有参构造传入线程名
public SaleThread(String name) {
// TODO Auto-generated constructor stub
super(name);
}
//无参构造传入线程名
public SaleThread() {
}
//重写run()方法,将售票动作放入其中
public void run() {
while(true) {
//在锁外使用sleep(),以便于更好的解决复现问题
try {
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
//使用synchronized需要锁统一资源,不然没效果,所以将obj初始化为static静态。
//但让也可以使用字符串 synchronized("lock");lock随便输入
synchronized(obj) {
//还有余票---出票
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"号窗口第"+ticket+"票 正在出票...");
ticket--;
}else {
//车票售罄
System.out.println("车票已售罄,下次请趁早...");
//退出
System.exit(0);
}
}
}
}
}
方法二 实现Runnable接口
package sell;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
class Selldemolist implements Runnable {
Scanner in=new Scanner(System.in);
int tickets=in.nextInt();
private int salenum=0;
public void sellTickets() {
synchronized (this) {
if (tickets > 0) {
tickets--;
salenum++;
System.out.println(Thread.currentThread().getName() + "已经购买编号为"+salenum+"的票");
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time=sdf.format(date);
System.out.println("出票时间为:"+time);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("___________________________________");
System.out.println(" ");
}
}
}
public void run() {
while (tickets > 0) {
sellTickets();
try {
Thread.sleep(400);
if(tickets==0){
System.out.println("非常抱歉,售票已经结束,请明天再来!");
System.exit(-1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Selldemo1 {
public static void main(String[] args) {
Selldemolist ticket=new Selldemolist();
Thread mary = new Thread(ticket,"玛丽");
Thread jack = new Thread(ticket,"杰克");
Thread rose=new Thread(ticket,"柔丝");
Thread black=new Thread(ticket,"布莱克");
mary.start();
jack.start();
rose.start();
black.start();
}
}
案例二
方法一 继承Thread类
package Demo;
public class Sellticket1 {
public static void main(String[] args) {
//创建3个线程,并开启
for(int i=1;i<4;i++){
new TicketWindow("窗口"+i+":").start();
}
}
}
//方法1.继承Thread类
class TicketWindow extends Thread{
private static int ticket = 100;//车票数被共享,所以定义为static
private static Object obj = new Object();//通过锁来保证线程不会重复访问
//有参构造传入线程名
public TicketWindow(String name) {
super(name);
}
public TicketWindow() {
}
//重写run()方法,将售票动作放入其中
public void run() {
while (true) {
//在锁外使用sleep( );以便于更好的解决复现问题
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//也可以使用字符串 synchronized("lock");lock随便输入
synchronized (obj) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "第-- "+ ticket + " --票正在出票...");
ticket--;
} else {
System.out.println("票已售完 下次再见!!");
System.exit(0);
}
}
}
}
}
方法二 实现Runnable接口
package Demo;
public class Sellticket2 {
public static void main(String[] args) {
Windows sc = new Windows();
//创建3个线程,并开启
for(int i=1;i<4;i++){
new Thread(sc,"窗口"+i).start();
}
}
}
//方法2.实现Runnable接口
class Windows implements Runnable{
private int ticket = 100;
private Object obj = new Object(); //定义一个线程同步对象
public void run() {
while(true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//同步锁
synchronized(obj){
if(ticket > 0){
System.out.println(Thread.currentThread().getName()+" 售出第-- "+ticket +" --张票");
ticket--;
}else{
System.out.println("票已售完 下次再见!!");
System.exit(0);
}
}
}
}
}
案例三
方法一 继承Thread类
package xiancheng;
import java.util.Scanner;
class thread extends Thread {
public static int num, num1;
public static Object obj = new Object();
public int i = 1;
public thread(String name) {
super(name);
}
public thread() {
}
@Override
public void run() {
// TODO 自动生成的方法存根
while(true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
synchronized(obj) {
if(num > 0) {
System.out.println("售票点:" + Thread.currentThread().getName() + " 当前卖出票号:" + (num1 - num + 1) );
num--;
} else {
System.out.println("已卖完");
System.exit(0);
}
}
}
}
public void getChePiao(int chePiao) {
num = chePiao;
num1 = chePiao;
}
}
public class DoThread {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int i;
Scanner scanner = new Scanner(System.in);
System.out.print("请问要卖多少张票:");
new thread().getChePiao(scanner.nextInt());
for(i = 1 ; i <= 4 ; i++) {
new thread("" + i).start();
}
}
}
方法二 实现Runnable接口
package xiancheng;
import java.util.Scanner;
class Runn implements Runnable {
public int num, i = 1, num1;
@Override
public void run() {
// TODO 自动生成的方法存根
while(true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
doRun();
if(num <= 0) {
System.exit(0);;
}
}
}
public synchronized void doRun() {
if(i > 0 && i <= num1) {
System.out.println("售票点:" + Thread.currentThread().getName() + " 当前卖出票号:" + i);
i++;
num--;
} else if(num <= 0) {
System.out.println("已卖完");
System.exit(0);
}
}
public void getChePiao() {
Scanner scanner = new Scanner(System.in);
System.out.print("请问要卖多少张票:");
num = scanner.nextInt();
num1 = num;
}
}
public class DoRunnable {
public static void main(String[] args) {
// TODO 自动生成的方法存根
int i;
Runn runn = new Runn();
runn.getChePiao();
for(i = 1 ; i <= 4 ; i++) {
new Thread(runn, "" + i).start();
}
}
}
案例四
方法一 继承Thread类
package one;
import java.util.Scanner;
public class Sale {
private static int ticket,temp;
public static void main(String [] args) {
System.out.println("请输入您发放的票数:");
Scanner in = new Scanner(System.in);
String x = in.nextLine();
ticket = Integer.parseInt(x);
temp = ticket;
for(int i=1;i<6;i++) {
new sell1(" ["+i+"]",temp).start();
}
}
}
class sell1 extends Thread {
private static int ticket,temp1;
private static Object obj = new Object();
public sell1() {
}
public sell1(String name,int temp) {
super (name);
ticket = temp;
}
@Override
public void run() {
temp1 = ticket;
while (true) {
try {
Thread.sleep(100);
}
catch(InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
if(ticket>0) {
int a = temp1-ticket+1;
System.out.println("售票点:"+Thread.currentThread().getName()+ "\t当前票号: "+a);
ticket--;
}
else {
System.out.println("车票已经售完,下次请趁早...");
System.exit(0);
}
}
}
}
}
方法二 实现Runnable接口
package two;
import java.util.Scanner;
public class Sale2 {
public static void main(String [] args) {
int ticket1;
System.out.println("请输入您发放的票数:");
Scanner in = new Scanner(System.in);
String x = in.nextLine();
ticket1 = Integer.parseInt(x);
sell s = new sell(ticket1);
for(int i=1;i<6;i++) {
new Thread(s,"["+i+"]").start();
}
}
}
class sell implements Runnable{
private static int ticket,temp1;
private static Object obj = new Object();
public sell() {
}
public sell(int ticket1) {
ticket = ticket1;
}
@Override
public void run() {
temp1 = ticket;
while (true) {
try {
Thread.sleep(100);
}
catch(InterruptedException e) {
e.printStackTrace();
}
synchronized (obj) {
if(ticket>0) {
int a = temp1-ticket+1;
System.out.println("售票点:"+Thread.currentThread().getName()+ "\t当前票号: "+a);
ticket--;
}
else {
System.out.println("车票已经售完,下次请趁早...");
System.exit(0);
}
}
}
}
}
案例五
方法一 继承Thread类
package eclipse;
public class Ticket1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//首先创建5个线程,传入线程名:如[001]、[002]等,并将其开启。
int i;
for(i=1;i<+5;i++) {
new SaleThread("[00"+i+"]").start();
}
}
}
class SaleThread extends Thread{
//由于车票数要对公众共享,所以要定义为静态成员变量,数量定为100.
private static int ticket=100;
//通过锁来保证线程都不会被重复访问.
private static Object obj=new Object();
//把有参构造传入线程名
public SaleThread(String name) {
super(name);
}
public SaleThread(){
}
//重新写入run()方法,将售票动作放入其中;
@Override
public void run() {
while(true) {
//要在锁外使用sleep();
try {
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
//使用synchronized需要统一资源,不然没效果,所以将obj初始化为static静态.
//但让也可以使用字符串 synchronized("lock");lock随便输入
synchronized(obj) {
//还有余票——————出票
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"号窗口正在出票...票号:"+ticket);
ticket--;
}else {
//利用if,else语句来看看车票售出的情况,如果售出完成,则执行else下面的语句。
System.out.println("车票已经售完,下次请趁早买票!");
System.exit(0);
}
}
}
}
}
方法二 实现Runnable接口
package eclipse;
public class Ticket2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//首先得到对象
SaleSys a =new SaleSys();
//然后把对象放入线程中
for(int i=1;i<6;i++) {
new Thread(a,"[00"+i+"]").start();
}
}
}
class SaleSys implements Runnable{
//定义票的总数
private int ticket = 100;
//定义一个线程同步的对象
private Object obj=new Object();
@Override
public void run() {
while(true) {
try {
Thread.sleep(50);
}catch(InterruptedException e) {
e.printStackTrace();
}
//同步锁
synchronized(obj) {
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"号窗口正在售票...票号:"+ticket);
ticket--;
}else {
System.out.println("票已售完,请下次再来吧!");
System.exit(0);
}
}
}
}
}
案例六
方法一 继承Thread类
package com.hym.Threaded;
public class Sale_Thread{
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建五个窗口(线程)
for(int i = 1;i < 6;i++) {
new SaleThread("[0" + i + "]").start();
}
}
}
class SaleThread extends Thread{
//车票数为共享变量,静态变量定义用static,数量为100
private static int tickets = 100;
//通过锁使这个线程不会被重复访问
private static Object obj = new Object();
public SaleThread(String name) {
super(name);
}
public SaleThread() {
}
//重写run方法
@Override
public void run() {
while(true) {
try {
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
//将obj初始化为static静态
synchronized (obj) {
if(tickets > 0) {
System.out.println(Thread.currentThread().getName() + "号窗口第" + tickets-- + "票正在出票...");
}
else {
//车票售完
System.out.println("车票已售罄。");
System.exit(0);
}
}
}
}
}
方法二 实现Runnable接口
package com.hym.Threaded;
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
SaleSys s = new SaleSys();
//创建五个窗口(线程)
for(int i = 1;i < 6;i++) {
new SaleThread("[0" + i + "]").start();
}
}
}
class SaleSys implements Runnable{
//车票数为共享变量,静态变量定义用static,数量为100
private static int tickets = 100;
//通过锁使这个线程不会被重复访问
private static Object obj = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
//将obj初始化为static静态
synchronized (obj) {
if(tickets > 0) {
System.out.println(Thread.currentThread().getName() + "号窗口第" + tickets-- + "票正在出票...");
}
else {
//车票售完
System.out.println("车票已售罄。");
System.exit(0);
}
}
}
}
}
案例七
方法一 继承Thread类
package 售票;
public class duo2 {
public static void main(String[] args) {
for(int i=1; i<4; i++){
chuangkou2 sp = new chuangkou2();
sp.setName(i+"号窗口");
sp.start();
}
}
}
class chuangkou2 extends Thread{
private int tickets = 10;//车票总量
public void run(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName() + "准备售票");
tickets--;
System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");
break;
}
}
}
}
方法二 实现Runnable接口
package 售票;
public class duo{
public static void main(String[] args) {
chuangkou sp = new chuangkou();
for(int i=1; i<4; i++){
Thread t = new Thread(sp, i +"号窗口");
t.start();
}
}
}
class chuangkou implements Runnable{
private int tickets = 10;
public void run(){
while(true){
if(tickets>0){
shoupiao();
}
else{
System.out.println(Thread.currentThread().getName() + "余票不足,停止售票!");
break;
}
}
}
public synchronized void shoupiao(){
if(tickets>0){
System.out.println(Thread.currentThread().getName() + "准备售票");
tickets--;
System.out.println(Thread.currentThread().getName() + "卖出一张,剩余票数:" + tickets + "张");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
案例八
方法一 继承Thread类
package Thread;
import java.util.Calendar;
import javax.xml.crypto.Data;
import java.util.*;
class sale_Thread extends Thread
{
private static volatile int tickets=2000;
public synchronized void run()
{
while(tickets>0)
{
use();
}
}
private synchronized static void use()
{
if(tickets>0)
{
System.out.println(Thread.currentThread().getName() +"售出第"+tickets--+"张票");
}
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// // TODO 自动生成的 catch 块
// e.printStackTrace();
// }
}
public static String getWeekOfDate(Date date) {
String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0)
w = 0;
return weekDays[w];
}
public static void main(String[] args) {
Date date=new Date();
String w=getWeekOfDate(date);
System.out.println(w);
String u1="星期五",u2="星期六";
if(w.equals(u1)||w.equals(u2))
{
System.out.println("双休日期间,不予办理业务");
}
else
{
sale_Thread s1=new sale_Thread();
sale_Thread s2=new sale_Thread();
sale_Thread s3=new sale_Thread();
sale_Thread s4=new sale_Thread();
sale_Thread s5=new sale_Thread();
Thread t1=new Thread(s1,"售票窗口1");
Thread t2=new Thread(s2,"售票窗口2");
Thread t3=new Thread(s3,"售票窗口3");
Thread t4=new Thread(s4,"售票窗口4");
Thread t5=new Thread(s5,"售票窗口5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
}
方法二 实现Runnable接口
package Runable;
public class 售票系统2
{
public static int tickets=1000;
protected synchronized static void use()
{
if(tickets>0)
{
System.out.println(Thread.currentThread().getName() +"售出第"+tickets--+"张票");
}
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// // TODO 自动生成的 catch 块
// e.printStackTrace();
// }
}
public static void main(String[] args) {
Runner1 runner1 = new Runner1();
Runner2 runner2 = new Runner2();
Runner3 runner3 = new Runner3();
Thread thread1 = new Thread(runner1,"售票窗口1");
Thread thread2 = new Thread(runner2,"售票窗口2");
Thread thread3 = new Thread(runner3,"售票窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Runner1 extends 售票系统2 implements Runnable {
public void run() {
while(tickets>0)
use();
}
}
class Runner2 extends 售票系统2 implements Runnable { // 实现了Runnable接口,jdk就知道这个类是一个线程
public void run() {
while(tickets>0)
use();
}
}
class Runner3 extends 售票系统2 implements Runnable { // 实现了Runnable接口,jdk就知道这个类是一个线程
public void run() {
while(tickets>0)
use();
}
}
案例九
方法一 继承Thread类
package Thticket;
/*
* 继承Thread类方法售票*/
public class MyThread {
public static void main(String[] args) {
System.out.println("我是实现系统一");
for(int i=1;i<6;i++) {
new saleMyThread("第"+i+"窗口 ").start();
}
}
}
class saleMyThread extends Thread{
private static int tic=100;
//创建锁
private static Object obj = new Object();
//有参构造传入线程名
public saleMyThread(String name) {
super(name);
}
public saleMyThread() {
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
//0.1秒
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//同步锁
synchronized (obj) {
if (tic > 0) {
System.out.println(Thread.currentThread().getName() + "售出第"
+ tic + "票");
tic--;
}
else {
//车票售完
System.out.println("车票已售完,下次请趁早...");
System.exit(0);
}
}
}
}
}
方法二 实现Runnable接口
package Runticket;
/*
* 实现Runnable接口来售票*/
public class MyRunnable {
public static void main(String[] args) {
System.out.println("我是实现系统二");
//得到对象
saleMyRunnable mr=new saleMyRunnable();
for(int i=1;i<6;i++){
new Thread(mr,"第"+i+"窗口 ").start();
}
}
}
class saleMyRunnable implements Runnable{
//定义票的总数
private int tic = 100;
//定义一个线程同步对象
private Object obj = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
//0.1秒
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//同步锁
synchronized(obj) {
if(tic > 0){
System.out.println(Thread.currentThread().getName()+" 售出第 "+tic +" 张票");
tic--;
}else{
System.out.println("票已售完,请下次再来!");
System.exit(0);
}
}
}
}
}