并行:指两个或多个事件在同一时刻发生 强调时间点
并发:指两个或多个事件在同一时间段内发生 强调时间段
进程和线程
进程之间的通信很不方便,如此引出了线程,线程是进程里的一个执行任务,一个进程中开启多个执行任务,即多线程
创建线程和启动线程
创建线程 继承Java.lang.Thread类
实现Runnable
匿名实现
package _02_Implements;
public class InnerDemo {
public static void main(String[] args) {
new Thread(){
public void run(){
for(int i=0;i<1000;i++){
System.out.println("跳舞");
}
}
}.start();
new Thread(new Runnable(){
@Override
public void run() {
for(int i=0;i<1000;i++){
System.out.println("唱歌");
}
}
}).start();
}
}
线程继承和实现之间的区别
package _03_extendsPKimpl;
//三人同时吃100个苹果
public class Demo_extends {
public static void main(String[] args) {
new student("小红").start();
new student("小芳").start();
new student("小至").start();
}
}
class student extends Thread{
student(String name){
super(name);
}
private Integer num = 100;
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(this.getName()+"吃了"+ num-- + "个苹果");
}
}
}
package _03_extendsPKimpl;
public class Demo_implements {
public static void main(String[] args) {
Apple apple = new Apple();
new Thread(apple,"a").start();
new Thread(apple,"b").start();
new Thread(apple,"c").start();
}
}
class Apple implements Runnable{
private Integer num = 100;
@Override
public void run() {
for(int i =0;i<100;i++){
if(num > 0){
System.out.println(Thread.currentThread().getName()+"吃了"+ num-- );
}
}
}
}
同步操作
当多个线程同时访问一个资源的时候,可能会出现线程安全问题
方法覆盖需要遵循一同二小一大(方法名相同,子类访问更加具体的类型,子类不能抛出新的异常,访问修饰符要大于等于父类的)
synchronized代码块
package _04_synchronized;
public class Demo_implements {
public static void main(String[] args) {
Apple apple = new Apple();
new Thread(apple, "a").start();
new Thread(apple, "b").start();
new Thread(apple, "c").start();
}
}
class Apple implements Runnable {
private Integer num = 100;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (this) {
if (num > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "吃了"
+ num--);
}
}
}
}
}
同步方法
如果是非static的方法,那么监听的是this (这里操作StringBuffer和StringBuilder中的append方法)
吐过是static修饰的方法,那么监听的是所在方法类的字节码对象(单例中懒汉式保证线程安全)
package _04_synchronized;
public class Demo_Method {
public static void main(String[] args) {
danli d1 = danli.getInstance();
danli d2 = danli.getInstance();
System.out.println(d1 == d2);
}
}
class danli{
private danli(){}
private static danli instance = null;
synchronized public static danli getInstance(){
if(instance == null){
instance = new danli();
}
return instance;
}
}
锁机制 jdk1.5开始
package _04_synchronized;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo_Lock {
public static void main(String[] args) {
Apple3 a = new Apple3();
new Thread(a, "a").start();
new Thread(a, "b").start();
new Thread(a, "c").start();
}
}
class Apple3 implements Runnable {
private Integer num = 100;
//创建锁
private final Lock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 100; i++) {
takeAway();
}
}
private void takeAway() {
lock.lock();
try {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "吃了"
+ num-- + "个苹果.");
}
} finally {
lock.unlock();
}
}
}
小结
1:什么是并发/并行.
2:进程和线程的区别.(面试题)
3:创建和启动线程的两种方式.
1):继承Thread类.
2):实现Runnable接口.
4):解决多线程并发时,线程不安全情况.
步骤: 先做一个线程不安全的案例.
1):使用同步代码块来解决.
2):使用同步方法来解决.
3):使用Lock来解决.