多线程
程序完成并发操作
构造函数
Thread(Runnable target)
void run()函数:执行程序代码
public class Thread
{
private Runnable r;
public Thread(Runnable r)
{
this.r = r;
}
}
public class ThreadTest
{
public static void main(String[] args)
{
Thread t1 = new Thread(new ATask);
Thread t2 = new Thread(new BTask);
t1.start();
t2.start();
}
}
class ATask implements Runnable//提供runnable接口,里面只有run函数,是线程运行的代码
{
public void run()//Thread代码一定封装在run()函数中
{
for(int i = 0;i < 100;i++)
System.out.println("ATask");
}
}
class BTask implements Runnable
{
public void run()//Thread代码一定封装在run()函数中
{
for(int i = 0;i < 100;i++)
System.out.println("BTask");
}
}
输出结果:100个ATask和100个BTask交替出现,但顺序可能无序,因为线程调度是操作系统做的
final 类型
//final修饰的类不能有派生类
//final修饰的函数表示后序不允许重载
//final和const的区别
final Student a = new student();
//a不能指向别的,但是student的东西可以修改
匿名类
匿名类没有名字,没有构造函数
K k = new K() { };//花括号内的叫初始化代码,有多段按顺序执行,初始化代码先于构造函数
匿名类访问需要通过父类型
sleep(10)函数,实际睡眠时间会长于10,因为完成睡眠后操作系统可能正忙。
锁
将并行操作转成串行
使用关键字synchronized修饰函数
synchronized void push()
每一个对象都有一把排他的对象锁
谁先获得钥匙由虚拟机决定,虚拟机不保证获得钥匙顺序,但是一般都是先来先获得
class A//一把锁
{
int x,y;
double i,j;
synchornized void a();//访问i,j
synchornized void b();//访问i,j
synchornized void c();//访问x,y
synchornized void d();//访问x,y
}
class A//2把锁
{
int x,y;
double i,j;
Object lock1 = new int[0];
Object lock2 = new int[0];
void a(){synchornized(lock1){} };//访问i,j
}
死锁问题
wait()的线程没有释放锁
- wait()函数:
- 封装在object上
- 必须持有对象锁才能调用这个函数
- 执行完成后,CPU不分配时间片,释放对象锁
- notifyAll()函数可以唤醒所有该对象正在阻塞的线程
- notify()函数唤醒一个该对象正在阻塞的线程,不保证顺序
while(条件)//阻塞条件
{wait();}
例:
栈满放不进去:wait()
此时取数据,执行notify()
此时再取数据,执行wait()
此时放数据,执行notify()
执行notifyAll()会带来更好的安全性,反正唤醒多了也会再次阻塞
但是效率低一些,因为还要再次阻塞
常用:对象池
初始化时创建几百个对象,成一个集合,标记是否占用,供以后的占用,提高速度。
new运算会很慢
ThreadLocal类
非常常用的类