线程创建 实现runable接口
public class CreateThread Runable{
public void run(){
}
}
匿名类
没有构造函数
父类的初始化 明确的调用
class A{
int i;
A(int i){
this.i = i;
}
public static void main(){
A a = new A(0);
A b = new A(2){//匿名类没有构造函数,这里的代码充当构造函数的作用
};
K k = new K(){//K是抽象的接口,这里调用的是Object的构造函数的,不是接口的构造函数
}
}
}
//匿名类没有类型,只能用父类的引用调用
new A(0){public void a(){}}.a();
内部类
class A {
class C{//该类的定义依赖于A类的对象
}
想不被依赖
static class C{
}
static abstract 可以同时修饰类,不可以同时修饰函数
void a(){
}
}
一个语法现象
class A {
int i = 0;
class B {
int t;
void a(){
//调用两个i
A.this.i = 9;
B.this.i = 9
}
}
}
sleep函数会抛出检查异常,需要放在try catch 里面
创建线程的方法
继承Thread 重写run方法
Thread t3 = new Thread(){public void run(){}};
实现Runable 接口
Thread t4 = new Thread(new Runable(){public void run(){}});
多线程编程存在临界区问题
两个或多个线程访问全局变量的时候会出现数据的紊乱
解决方案 加锁 (例如:排号机)...这里有故事
synchronized public char pop(){//同步控制
index--;
return data[index];
}
synchronized 可以修饰函数或者代码段
执行同步代码之前必须抢到对象的锁 执行完之后释放锁
将同步的程序 变成串行的 同步的
处于争夺锁的线程,都处于阻塞状态时,虚拟机不保证线程对的强锁顺序,但是一般是先进入阻塞状态的线程优先抢到锁
访问类的成员变量 即全局变量的时候就需要加上同步约束
决绝冲突的办法 一个是加锁 一个是数据复制
public void a(){
synchronized(data){
//这里是同步代码
}
}
划分不同的同步块
class A {
int i,j;
double x,y;
private Object lock1 = new byte[0];
private Object lock2 = new byte[0];
a(){
synchronized(lock1){
x,y;
}
}
b(){
synchronized(lock1){
x,y;
}
}
c(){
synchronized(lock2){
i,j;
}
}
d(){
synchronized(lock2){
i,j;
}
}
}
wait
执行wait操作的线程,释放CPU的执行权,同时释放锁
synchronized public char pop() {
while(index==0){
try{
wait();//释放锁
}catch(e){
e.printStackTrace();
}
}
data[index] = c;
index++;
notify();//唤醒一个处于wait线程,一般是最先阻塞的线程
}
volatile
只能修饰成员变量,保证对这个数据的操作是原子的