1.饿汉式线程安全的单例模式
//饿汉式线程安全——单例模式
public class Singleton {
//定义本类的一个私有实例对象
private static volatile Singleton single = null;
//私有化构造
private Singleton() {}
//因为不能创建对象,对外提供静态方法
public static Singleton getSingleton() {
if(single == null) {//先判断是否创建该类的单例对象single
synchronized(Singleton.class) {
/*可能多个线程都同时进行第一层if判断在锁外面等待,当一个线程创建完成释放锁后,
* 如果不加判断则会导致再次创建对象
*/
if(single == null) {
single = new Singleton();
}
}
}
return single;
}
}
2.多线程实现两个线程交替打印20以内的数
//线程交替打印
public class ThreadPrint {
public static void main(String[] args) {
ThreadCase one = new ThreadCase();
Thread t1 = new Thread(one);
Thread t2 = new Thread(one);
t1.start();
t2.start();
}
}
class ThreadCase implements Runnable{
public int num = 0;//线程共享资源变量
@Override
public void run() {
for(;num<=20;num++) {
synchronized (this) {
notify();//每次进来先唤醒等待的线程
System.out.println(Thread.currentThread().getName()+":"+num);
try {
Thread.sleep(1000);
if(num!=20) {//不加判断,程序打印完一直处于等待状态
wait();//每个线程执行打印后等待,让下一个线程进入
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
3.实现死锁程序
/**示例:死锁*/
class ZhangSan{
public void say() {
System.out.println("张三说:你给我书,我就给你画");
}
public void get() {
System.out.println("张三 获得了书");
}
}
class Lisi{
public void say() {
System.out.println("李四:你给我画,我就给你书");
}
public void get() {
System.out.println("李四获得了画");
}
}
class DeadLockThread implements Runnable{
private static ZhangSan zhangSan = new ZhangSan();
private static Lisi lisi = new Lisi();
public boolean tag = false;//标志量,保证张三和李四进入对应的条件分支
@Override
public void run() {
if(tag == true) {//张三
synchronized (zhangSan) {
zhangSan.say();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lisi) {
zhangSan.get();
}
}
}else {//李四
synchronized (lisi) {
lisi.say();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (zhangSan) {
lisi.get();
}
}
}
}
}
//测试死锁
public class DeadLock {
public static void main(String[] args) {
DeadLockThread td1 = new DeadLockThread();
td1.tag = true;
DeadLockThread td2 = new DeadLockThread();
td2.tag = false;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start();
}
}
4.数组蓄水问题
问题分析:
对于每个柱子,找到其左右两边最高的柱子,该柱子能容纳的面积就是min(max_left, max_right) - height,这个是问题的本质所在,理解了这个下面的方法就容易理解了
//数组蓄水问题
public class StorageArray {
/**
* 先找到数组中的最高点。该点将数组分为左右两半。对于左半侧,从左向右处理;对于右半侧,从右向左处理。
* 处理的时候只需考虑已扫描一侧的高度即可,因另一侧有数组最高点,无需担心蓄水问题。
* 该方法的时间复杂度O(N),空间复杂度O(1)
* @param arr:求蓄水量的数组
*/
public static int storageArray(int[] arr) {
int maxPointIndex = 0;//数组中的最高点
//先查找数组的最高点的索引
for (int i = 1; i < arr.length; i++)
if (arr[i] > arr[maxPointIndex])
maxPointIndex = i;
//声明该数组的蓄水量water
int water = 0;
//计算最高点左边的蓄水量
for (int i = 1, leftMovePointIndex = 0; i < maxPointIndex; i++) {
//如果左边相邻的两个位置,靠后的位置比前面位置的值大,则向后移动一位再次比较
if (arr[i] > arr[leftMovePointIndex]) {
leftMovePointIndex = i;
} else {
//靠后的位置比前面位置的值小,则证明可以积水,该蓄水量就是两个位置的之差
water += arr[leftMovePointIndex] - arr[i];
}
}
//计算最高点右边的蓄水量,跟左边的逻辑一样
for (int i = arr.length - 2, rightMovePointIndex = arr.length - 1; i > maxPointIndex; i--) {
if (arr[i] > arr[rightMovePointIndex])
rightMovePointIndex = i;
else
water += arr[rightMovePointIndex] - arr[i];
}
//最终返回总的蓄水量
return water;
}
//测试
public static void main(String[] args) {
int[] arr = {3,1,2,5,2,1,3};
System.out.println("该数组下雨蓄水量为:"+storageArray(arr));
}
}