昨天知识总结
TreeMap的注意点 增强for循环 Arrays 可变参数 Collections 多线程
多线程的基础 多线程的原理 多线程的实例—垃圾回机制 多线程的创建方式
线程
线程创建的两种方法
实例:实现两个售票员售票
分析:创建4个线程,–4个售票员 任务:只需要一个 数据:只需要一个 创建线程的第一种方法:通过创建Thread类的子类—让run留在了线程的内部,造成任务与线程的绑定,操作不方便
public static void main ( String[ ] args) {
Seller seller1 = new Seller ( ) ;
Seller seller2 = new Seller ( ) ;
Seller seller3 = new Seller ( ) ;
Seller seller4 = new Seller ( ) ;
seller1. start ( ) ;
seller2. start ( ) ;
seller3. start ( ) ;
seller4. start ( ) ;
}
class Seller extends Thread {
static int num = 40 ;
public void run ( ) {
for ( int i = 0 ; i < 10 ; i++ ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + " i:" + i+ " " + -- num) ;
}
}
}
第二种方式:让线程与任务分离----将run从线程中独立出来,好处:操作起来更方便,那个线程想工作,我就把任务交给谁。
public static void main ( String[ ] args) {
Ticket ticket = new Ticket ( ) ;
Thread seller1 = new Thread ( ticket) ;
Thread seller2 = new Thread ( ticket) ;
Thread seller3 = new Thread ( ticket) ;
Thread seller4= new Thread ( ticket) ;
seller1. start ( ) ;
seller2. start ( ) ;
seller3. start ( ) ;
seller4. start ( ) ;
}
}
class Ticket implements Runnable {
int num = 40 ;
public void run ( ) {
for ( int i = 0 ; i < 10 ; i++ ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + " i:" + i+ " " + -- num) ;
}
}
}
线程安全和解决方法
线程安全问题: 分析:4个线程共用一个数据,出现了-1,-2,-3等错误的数据 具体分析:1.共用了一个数据 2.共有语句有多余,一个线程使用cpu,没有使用完,CPU被抢走,当再次抢到cpu的时候,直接执行后面的语句,造成了错误的发生 解决: 在代码中使用同步代码块儿(同步锁) 解释:在某一段任务中,同一时间只允许一个线程执行任务,其他的线程即使抢到了CPU,也无法进入当前的任务区间,只有当当前的线程将任务执行完后,其他的线程才能有资格进入 同步代码块儿的构成: synchronized(锁(对象)){ 同步的代码 } 对做为锁的对象的要求:1.必须是对象 2.必须保证被多个线程共享 可以充当锁的:
一个普通的对象 当前对象的引用----this 类的字节码文件 同步代码块儿的特点:
可以保证线程安全 由于每次都要进行判断处理,所以降低了执行效率 总结:什么时候使用同步代码块儿?
多个线程共享一个数据 至少有两个线程
public static void main ( String[ ] args) {
Ticket1 ticket = new Ticket1 ( ) ;
Thread seller1 = new Thread ( ticket) ;
Thread seller2 = new Thread ( ticket) ;
Thread seller3 = new Thread ( ticket) ;
Thread seller4= new Thread ( ticket) ;
seller1. start ( ) ;
seller2. start ( ) ;
seller3. start ( ) ;
seller4. start ( ) ;
}
}
class Ticket1 implements Runnable {
int num = 20 ;
boolean flag = false ;
Object object = new Object ( ) ;
public void run ( ) {
try {
Thread. sleep ( 100 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
while ( ! flag) {
synchronized ( this ) {
try {
Thread. sleep ( 100 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
if ( num > 0 ) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + " " + -- num) ;
} else {
flag = true ;
}
}
}
}
}
同步函数
实例:两个人向同一个账户里面存钱 一人存三次,每次存100 注意:1.当一个类中同时存在多个synchronized修饰的代码块儿或函数式,要想安全,就必须让他们后面的对象一致,因为只有同一把锁才安全。 静态同步函数的锁是其所属类的字节码文件 理解synchronized关键字 1.synchronized的关键字的作用域有两种:
a. 是某个对象实例内:synchronized aMethod(){}可以防止多个线程同事访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中一个synchronized方法,其他线程不能同时访问这个对象中的任何一个synchronized方法)。这时不同的对象实例的synchronized方法是不想干扰的。也就是说,其他线程照样可以同时访问相同类的另一个对象实例中的synchronized方法。
public static void main ( String[ ] args) {
Ticket2 ticket2 = new Ticket2 ( ) ;
Thread thread1 = new Thread ( ticket2) ;
Thread thread2 = new Thread ( ticket2) ;
thread1. start ( ) ;
thread2. start ( ) ;
}
}
class Ticket2 implements Runnable {
Bank bank = new Bank ( ) ;
@Override
public void run ( ) {
for ( int i = 0 ; i < 3 ; i++ ) {
bank. addMany ( 100 ) ;
}
}
}
class Bank {
int sum;
public synchronized void addMany ( int money) {
sum+= money;
System. out. println ( sum) ;
}
}
b. 是某个类的范围:synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static方法。他可以对类的所有对象实例起到作用。
public static void main ( String[ ] args) {
Ticket2 ticket2 = new Ticket2 ( ) ;
Thread thread1 = new Thread ( ticket2) ;
Thread thread2 = new Thread ( ticket2) ;
thread1. start ( ) ;
thread2. start ( ) ;
}
}
class Ticket2 implements Runnable {
Bank bank = new Bank ( ) ;
@Override
public void run ( ) {
for ( int i = 0 ; i < 3 ; i++ ) {
bank. addMany ( 100 ) ;
}
}
}
class Bank {
int sum;
public synchronized static void addMany ( int money) {
}
}
2.除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是:synchronized(this){//区块/},它的作用域是当前对象;
public static void main ( String[ ] args) {
Ticket2 ticket2 = new Ticket2 ( ) ;
Thread thread1 = new Thread ( ticket2) ;
Thread thread2 = new Thread ( ticket2) ;
thread1. start ( ) ;
thread2. start ( ) ;
}
}
class Ticket2 implements Runnable {
Bank bank = new Bank ( ) ;
@Override
public void run ( ) {
for ( int i = 0 ; i < 3 ; i++ ) {
bank. addMany ( 100 ) ;
}
}
}
class Bank {
int sum;
public void addMany ( int money) {
synchronized ( this ) {
sum+= money;
System. out. println ( sum) ;
}
}
}
3.synchronized关键字是不能被继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动式synchronizedf(){},而是变成了f(){},继承类需要你显示的指定它的某个方法为synchronized方法
在懒汉式单例中添加锁
class SingleInstance1 {
private static SingleInstance1 instance1;
private SingleInstance1 ( ) {
}
public static SingleInstance1 getInstance ( ) {
if ( instance1 == null) {
synchronized ( SingleInstance1. class ) {
if ( instance1 == null) {
instance1 = new SingleInstance1 ( ) ;
}
}
}
return instance1;
}
}
线程的停止
1.通过一个标识结束线程
public static void main ( String[ ] args) {
Test1 test1 = new Test1 ( ) ;
Thread thread = new Thread ( test1) ;
thread. start ( ) ;
try {
Thread. sleep ( 100 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
int i = 0 ;
while ( true ) {
if ( ++ i == 1000000000 ) {
test1. flag = false ;
break ;
}
}
}
}
class Test1 implements Runnable {
boolean flag = true ;
@Override
public void run ( ) {
while ( flag) {
System. out. println ( Thread. currentThread ( ) . getName ( ) + " 我们很嗨皮" ) ;
}
}
}
2.通过stop方法结束线程----有固有的安全问题,已经过时,不建议在使用
3.调用interrupt()方法结束线程----
原理: 线程可以调用wait()方法,让当前的线程处于钝化的状态(会立即释放CPU,并无法强CPU的状态,但当前的线程并没有死亡) 调用interrupt方法就是将处于wait状态下的线程停止 注意:wait方法必须在同步状态下使用
public class Demo7 {
public static void main ( String[ ] args) {
Test1 test1 = new Test1 ( ) ;
Thread thread = new Thread ( test1) ;
thread. start ( ) ;
try {
Thread. sleep ( 100 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
int i = 0 ;
while ( true ) {
if ( ++ i == 1000000000 ) {
thread. interrupt ( ) ;
break ;
}
}
}
}
class Test1 implements Runnable {
boolean flag = true ;
@Override
public synchronized void run ( ) {
while ( flag) {
try {
wait ( ) ;
} catch ( InterruptedException e) {
flag = false ;
System. out. println ( "InterruptedException" ) ;
}
System. out. println ( Thread. currentThread ( ) . getName ( ) + " 我们很嗨皮" ) ;
}
}
}