用户线程和守护线程:
- 用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
- 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
- 常见的守护线程:垃圾回收机制
将一个线程设置成守护线程:
public static void main(String[] args) {
MyDaemonThread myDaemonThread = new MyDaemonThread();
//如果希望当main线程结束后,子线程自动结束
//只需将子线程设置为守护线程即可
myDaemonThread.setDeamon(true);
//先设置好守护线程,再start
myDaemonThread.start();
for (int i = 1;i <= 10 ; i++) { //主线程
System.out.print("工作中~~~~~~");
Thread.sleep(1000);
}
}
class MyDaemonThread extends Thread{
public void run(){
for (; ; ) { //无限循环
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.print("哈哈哈哈哈~~~~~");
}
}
}
线程的生命周期:
线程7大状态:
- NEW:尚未启动的线程处于此状态
- RUNNABLE:在java虚拟机中执行的线程处于此状态
- BLOCKED:被阻塞等待监视器锁定的线程处于次状态
- WAITING:正在等待另一个线程执行特定动作的线程处于此状态
- TIMED_WAITING:正在等待另一个线程执行动作达到指定时间的线程处于此状态
- TERMINATED:已退出的线程处于此状态
线程同步机制:
- 在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。
- 也可以这样理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作
同步具体方法- Synchronized:
- 同步代码块:
synchronized(对象){ //得到对象的锁,才能操作同步代码
//需要被同步的代码
} -
synchronized还可以放在方法声明中,表示整个方法-为同步方法
public synchronized void m(String name){
//需要被同步的代码
}//实现接口的方式,使用synchronized实现线程同步
class SellTicket02 implements Runnable{
private int ticketNum = 100; //让多个线程共享ticketNum
private boolean loop = true;//1、public synchronized void sell(){} 就是一个同步方法
//2、这时锁在this对象
//3、也可以在代码块上写synchronize,同步代码块,互斥锁还是在this对象
public /synchronized/ void sell(){ //同步方法,在同一时刻,只能有一个线程来执行sell方法
synchronized (this){ //同步代码块
if (ticketNum <= 0) {
System.out.print(“售票结束“);
loop = false;
return ;
}
//休眠50毫
try{
Thread.sleep(50);
}catch(InterruptedException e){
e.printStackTrace();System.out.print("窗口" + Thread.currentThread().getName() + "售出了一张票" + "剩余票数" + (--ticketNum));
}
}
@Override
public synchronized void run(){
while(loop){
sell();
}
}
互斥锁:
-
Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性
-
每个对象都对应于一个可称为”互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
-
关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任意时刻只能由一个线程访问
-
同步的局限性:导致程序的执行效率要降低
-
同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
-
同步方法(静态的)的锁为当前类本身
//同步方法(静态的)的锁为当前类本身
//1、public synchronized static void m1(){} 锁是加载类上的 XX.class
public synchronized static void m1(){
}//2、如果在静态方法中,实现一个同步代码块
public static void m2(){
synchronized (XX.class){
System.out.print(“m2”);
}
}
注意:
- 同步方法如果没有使用static修饰:默认锁对象为this
- 如果方法使用static修饰,默认锁对象:当前类.class
- 实现的落地步骤:
- 需要先分析上锁的代码
- 选择同步代码块或同步方法
- 要求多个线程的锁对象为同一个即可
线程的死锁:
多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,,在编程时一定要避免死锁的发生
释放锁:
下面操作会释放锁:
- 当前线程的同步方法、同步代码块执行结束
案例:上厕所,完事出来
- 当前线程在同步代码块、同步方法中遇到break、return
案例:没有正常的完事,被叫出来修bug,不得已出来
- 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
案例:没有正常的完事,发现忘带纸,不得已出来
- 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
案例:没有正常完事,觉得需要酝酿下,所以出来等会再进去
下面操作不会释放锁:
- 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁
案例:上厕所,太困了,在坑位上眯了一会
- 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁
提示:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用
文件流:
文件在程序中是以流的形式来操作的
流:
- 数据在数据源(文件)和程序(内存)之间经历的路径
输入流:
- 数据从数据源(文件)和程序(内存)的路径
输出流:
- 数据从程序(内存)到数据源(文件)的路径
常用的文件操作:
创建文件对象相关构造器和方法:
new File(String pathname) //根据路径构建一个File对象
new File(File parent,String child) //根据父目录文件+子路径构建
new File(String parent,String child) //根据父目录+子路径构建
creatNewFile 创建新文件
例:
请在e盘下,创建文件 news1.txt news2.txt news3.txt,用3中不同方式创建
//方式一
public void create01(){
System filePath = "e:\\news1.txt";
File file = new File(filePath);
file.creatNewFile();
}
//方式二 根据父目录文件+子路径构建
//e:\\news2.txt
public void create02(){
File parentFile = new File("e:\\");
String fileName = "news2.txt"
//只有执行了creatNewFile方法,才会真正的在磁盘创建该文件
File file = new File(filePath);
file.creatNewFile();
}
//方式三 根据父目录+子路径构建
public void create03(){
String parentPath = "e:\\";
String fileName = "news3.txt";
File file = new File(parentPath,fileName);
file.creatNewFile();
}
获取文件信息:
- getName
-
getAbsolutePath
-
getParent
-
length
-
exists
-
isFile
-
isDirectory
public void info(){
//先创建文件对象
File file = new File(“e:\news1.txt”);//调用相应的方法,得到对应信息 System.out.print("文件名字" + file.getName()); System.out.print("文件绝对路径" + file.getAbsolutePath()); System.out.print("文件父级目录" + file.getParent()); System.out.print("文件大小(字节)" + file.length()); System.out.print("文件是否存在" + file.exists()); System.out.print("是不是一个文件" + file.isFile()); System.out.print("是不是一个目录" + file.isDirectory());
}