Java小细节(五)

上集 (Java小细节(四)

Object(所有类的根类)

  1. instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:
    boolean result = obj instanceof Class
      其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
      注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

包与包之间

  1. (default默认权限)
    在这里插入图片描述

多线程(重点)

  1. 在这里插入图片描述
  2. 创建线程的目的是为了开启一条执行路径,去是实现指定的代码和其他代码同时运行。而运行的指定代码就是这个执行路径的任务。
  3. jvm创建的主线程的任务都定义在了主函数中。
    而自定义的线程,Thread类用于描述线程,线程是需要任务的。所以Thread类也对任务进行描述,这个任务(代码)就通过Thread类中的run方法来体现。即run方法就是封装自定义线程运行任务的函数。

创建线程方式一:继承Thread类。
步骤:
1,定义一个类继承Thread类。
2,覆盖Thread类中的run方法。
3,直接创建Thread的子类对象创建线程。
4,调用start方法开启线程并调用线程的任务run方法执行。
74. 可以通过Thread.currentThread().getName()获取当前正在运行线程的名称。Thread-编号(从0开始)主线程名字就是main。
75. 在这里插入图片描述
76. 创建线程的第二种方式:实现Runnable接口。
1,定义类实现Runnable接口。
2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的函数进行传递。由于线程的任务都封装在Runnable接口子类对象的run方法中,要明确运行任务。
4,调用线程对象的start方法开启线程。
77. 实现Runnable接口的好处:
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。
将照面向对象的思想将任务封装成对象。
2,避免了java单继承的局限性。

卖票

在这里插入图片描述在这里插入图片描述
79. 出现线程安全问题:卖出0,-1号的票。
原因:
1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条。
解决方法:
1,同步代码块

Object obj=new Object();//相当于“同步锁”,注意得只有一个
synchronized(obj){//或者传所属对象this
	//需要被同步的代码;
}

2,同步函数

public synchronized void add(){
	//需要被同步的代码
}//同步函数,同步锁是this
//静态同步函数,同步锁是该函数所属字节码文件对象,可以用getClass()方法获取,也可以用 类名.class表示

同步的好处:解决了线程安全问题。
同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁。
同步的前提:同步中必须有多个线程并使用同一个锁。
80. 单例模式
1,懒汉式单例

public class LazySingleton
{
    private static volatile LazySingleton instance=null;    //保证 instance 在所有线程中同步
    private LazySingleton(){}    //private 避免类在外部被实例化
    public static  LazySingleton getInstance(){
        if(instance==null){//提高效率
        	synchronized(LazySingleton.class){
        		if(instance==null){
            		instance=new LazySingleton();
        		}
        	}
        }
        return instance;
    }
}
/*
1,保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性)
2,禁止进行指令重排序。(实现有序性)
3,volatile 只能保证对单次读/写的原子性。i++ 这种操作不能保证原子性。
*/

2,饿汉式单例

public class HungrySingleton
{
    private static final HungrySingleton instance=new HungrySingleton();
    private HungrySingleton(){}
    public static HungrySingleton getInstance(){
        return instance;
    }
}
  1. 死锁
class DeadLock implements Runnable
{
	private boolean state;
	DeadLock(boolean state){this.state=state;}
	public void run(){
		if(state){
			synchronized(Lock.locka){
				System.out.println(Thread.currentThread().getName()+"...a");
				synchronized(Lock.lockb){
					System.out.println(Thread.currentThread().getName()+"...b");
				}
			}
		}
		else{
			synchronized(Lock.lockb){
				System.out.println(Thread.currentThread().getName()+"...b");
				synchronized(Lock.locka){
					System.out.println(Thread.currentThread().getName()+"...a");
				}
			}
		}
	}
}

class Lock
{
	public static final Object locka=new Object();
	public static final Object lockb=new Object();
}

class DeadLockTest
{
	public static void main(String[] args){
		DeadLock a=new DeadLock(true);
		DeadLock b=new DeadLock(false);
		Thread t1=new Thread(a);
		Thread t2=new Thread(b);
		t1.start();
		t2.start();
	}
}
  1. 等待/唤醒机制
    涉及方法:
    1,wait();//让线程处于冻结状态(没有执行资格,没有执行权),被wait的线程会被储存到线程池中。
    2,notify();//唤醒线程池中一个线程(任意)。
    3,notifyAll();//唤醒线程池中的所有线程。

这些方法都必须定义在同步中。
因为这些方法是用于操作线程状态的方法。
必须要明确到底操作的是哪个锁上的线程。
83. 多生产者,多消费者问题

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class BoundedBuffer {
    final Lock lock = new ReentrantLock();
    final Condition notFull  = lock.newCondition();
    final Condition notEmpty = lock.newCondition();

    final Object[] items = new Object[100];
    int putptr, takeptr, count;

    public void put(Object x)  {
        lock.lock();
        try {
            while (count == items.length)
                try { notFull.await(); }catch (InterruptedException e){}
            items[putptr] = x;
            if (++putptr == items.length) putptr = 0;
            ++count;
            System.out.println(Thread.currentThread().getName()+"...生产了一只烤鸭,现有烤鸭"+count+"只");
            notEmpty.signal();
        } finally { lock.unlock(); }
    }

    public Object take()  {
        lock.lock();
        try {
            while (count == 0)
                try { notEmpty.await(); }catch (InterruptedException e){}
            Object x = items[takeptr];
            if (++takeptr == items.length) takeptr = 0;
            --count;
            System.out.println(Thread.currentThread().getName()+"......消费了一只烤鸭,现有烤鸭"+count+"只");
            notFull.signal();
            return x;
        } finally { lock.unlock(); }
    }
}
class Producer implements Runnable{
    private BoundedBuffer r;
    Producer(BoundedBuffer r){
        this.r=r;
    }
    public void run(){
        while(true)
            r.put(new Object());
    }
}

class Consumer implements Runnable{
    private BoundedBuffer r;
    Consumer(BoundedBuffer r){
        this.r=r;
    }
    public void run(){
        while(true)
            r.take();
    }
}

class Test{
    public static void main(String[] args){
        BoundedBuffer r=new BoundedBuffer();
        Producer p=new Producer(r);
        Consumer c=new Consumer(r);
        Thread t1=new Thread(p);
        Thread t3=new Thread(p);
        Thread t2=new Thread(c);
        Thread t4=new Thread(c);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

Lock接口:出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成显式锁操作。同时更为灵活。可以一个锁上加多组监视器。
84. wait和sleep区别
1,wait可以指定时间,也可以不指定。
sleep必须指定时间。
2,同步中,对cpu的执行权和锁的处理不同。
wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。
85. interrupt()方法能将线程从冻结状态强制恢复到运行状态,让线程具备cpu的执行资格。但是强制动作会发生InterruptedException异常,要进行异常处理。
86. void setDaemon(boolean on)标记为守护线程,非该线程结束,守护线程也结束。
87. join():在线程B中调用了线程A的Join()方法,将等到线程A执行完毕后,才会继续执行线程B,即将两个交替执行的线程合并为顺序执行的线程。
88. static void yield()暂停当前正在执行的线程对象,并执行自己或其他线程。
89. 在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值