在学习多线程时,如果联系操作系统来学习,会觉得很好理解。因为学习操作系统时候,有同步,互斥,锁的一些概念~
给个链接到上一篇~https://blog.csdn.net/zoweiccc/article/details/83002176
8.加入线程
(1)join,当前线程暂停,等待指定的线程执行结束后,当前线程再继续
(2)join(int),可以等待指定的毫秒之后继续,交替继续
9.礼让线程
yield让出cpu
10.设置线程的优先级,最小的优先级是1,最大是10,默认是5
setPriority()
11.什么情况下需要使用同步
如果多线程并发,有多段代码同时执行时,我们希望某一段代码执行的过程中cpu不要切换到其他线程工作,这时就需要同步
如果两段代码是同步的,那么同一时间只能执行一段,在一段代码没执行结束之前,不会执行另一段代码
12.同步代码块
使用synchronize关键字加上一个锁对象来定义一段代码,就叫做同步代码块
多个同步代码块如果使用相同的锁对象,那么他们就是同步的
13.同步方法
使用synchronized关键字修饰的一个方法,该方法中所有的代码都是同步的
非静态的同步方法的锁对象是this,静态的同步方法的锁对象是该类的字节码对象,即Pr2.class
14.线程安全问题,用火车站售票例子解释
15.死锁:多线程同步时,如果同步代码嵌套,使用相同锁,就有可能出现死锁,为了避免,不要出现同步代码块嵌套
16.一般来说,通过查看类的源码,如果存在synchronized,则大部分可认为是线程安全的。
比如:Vector是线程安全的,ArrayList是线程不安全的
StringBuffer是线程安全的,StringBuilder是线程不安全的
Hashtable是线程安全的,HashMap是线程不安全的
package pra_20;
public class J_39 {
/**
* @param args
*/
public static void main(String[] args) {
//8.加入线程
final Thread th1=new Thread(){
public void run(){
for(int i=0;i<10;i++){
System.out.println("1");
}
}
};
Thread th2=new Thread(){
public void run(){
for(int i=0;i<10;i++){
if(i==2){
try {
th1.join(); //匿名内部类在使用所在方法中的局部变量时,必须用final修饰
//th1.join(1)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("2");
}
}
};
th1.start();
th2.start();
//9.礼让线程
new Mythread2().start();
new Mythread2().start();
//10.设置线程的优先级
Thread th3=new Thread(){
public void run(){
for(int i=1;i<1000;i++){
System.out.println(getName()+"~~~~a");
}
}
};
Thread th4=new Thread(){
public void run(){
for(int i=1;i<1000;i++){
System.out.println(getName()+"~~~~b");
}
}
};
th3.setPriority(10);
th4.setPriority(3);
th3.start();
th4.start();
//12.同步代码块
final Pr p1=new Pr();
new Thread(){
public void run(){
while(true){
p1.pri();
}
}
}.start();
new Thread(){
public void run(){
while(true){
p1.pri2();
}
}
}.start();
//13.同步方法
final Pr2 p2=new Pr2();
new Thread(){
public void run(){
while(true){
p2.pri();
}
}
}.start();
new Thread(){
public void run(){
while(true){
p2.pri2();
}
}
}.start();
//14.线程安全问题
new Ticket().start();
new Ticket().start();
new Ticket().start();
new Ticket().start();
}
}
class Ticket extends Thread{
private static int ticket=100;
public synchronized void run(){
while(true){
synchronized(Ticket.class){
if(ticket<=0)
break;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("这是第"+ticket--+"张票");
}
}
}
}
//为了实现同步方法创建的类(非静态)
class Pr2{
Suo s=new Suo();
//非静态的同步方法的锁对象是this,静态的同步方法的锁对象是该类的字节码对象,即Pr2.class
public synchronized void pri(){ //同步方法只需要在方法上加synchronized关键字即可
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.println();
}
public void pri2(){
synchronized(this){
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
}
}
}
//为了实现同步方法创建的类(静态)
class Pr3{
Suo s=new Suo();
//静态的同步方法的锁对象是该类的字节码对象,即Pr3.class
public static synchronized void pri(){ //同步方法只需要在方法上加synchronized关键字即可
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.println();
}
public static void pri2(){
synchronized(Pr3.class){
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
}
}
}
//为了实现同步代码块创建的类
class Pr{
Suo s=new Suo(); //这个锁对象可以是任意的,随意创建一个对象即可,下面都表示的同一个锁
public void pri(){
synchronized (s) { //同步代码块,锁机制,当此方法运行完了才允许同步的执行,但参数不能创建匿名对象,因为匿名不是同一个
System.out.print("p");
System.out.print("q");
System.out.print("r");
System.out.print("s");
System.out.println();
}
}
public void pri2(){
synchronized (s) {
System.out.print("a");
System.out.print("b");
System.out.print("c");
System.out.print("d");
System.out.println();
}
}
}
class Suo{
}
class Mythread2 extends Thread{
public void run(){
for(int i=1;i<1000;i++){
if(i%10==0){
Thread.yield(); //让出cpu
}
System.out.println(getName()+"~~~~"+i);
}
}
}