转换流:
OutputStreamWriter:将字节输出流变为字符输出流。
InputStreamReader:将字节输入流变为字符输入流。
所有的读取都是对字节进行操作,只是另外开辟一点内存空间来进行字节和字符的转换。
转换流:
OutputStreamWriter:将字节输出流变为字符输出流。
InputStreamReader:将字节输入流变为字符输入流。
所有的读取都是对字节进行操作,只是另外开辟一点内存空间来进行字节和字符的转换。
设置并取得数据会产生:
数据不完整,明明是好人,结果成败类了;
数据的重复操作问题(重新设置或重复取出)
依然也是一个抽象类:如果要文件读取使用FileReader操作;reader并没有方法可以直接读取数据为字符串。只能通过数组来进行数据的读取操作。他支持char类型的读取。
字符输出流:writer:
1.write(String str):接受char类型,这个可以输出字符串
操作文件用FileWriter子类:
字节输入流:InputStream:
1.read(byte[] b):读取数据到字节数组中,返回数据的读取个数
2.read(byte[] b,int off,int len):读取部分数据到字节数组中
3.abstract read():读取单个字节:
是抽象的,使用FileInputStream来完成。
字节输出流:outputStream:
write(byte[] b) :将给顶的字节数组全部输出
write(byte[],int off,int len):部分输出
abstract write():输出单个字节
outputStream是一个抽象类,要想为父类实例化,那么就需要使用子类。以为方法名称都在父类定义好了,所以此处我们所关注的只有子类的构造方法。如果要进行文件的操作,可以使用FileOutputStream(File file):覆盖
追加内容:FileOutputStream(File file,boolean append):
在进行输出的时候所有的文件都会自动创建。
同步的本质:一个线程等待另一个线程执行完毕后才可以继续,但是如果几个相关的线程彼此之间都在等待着,那么就会造成死锁。
同步是指所有的线程不是一起进入到方法中执行,而是按照顺序一个一个进来
两种处理方法:同步代码块,同步方法
1. 同步代码块必须锁定对象,所以一般可以锁定当前对象:this
class MyThread implements Runnable{
public int ticket=10;
@Override
public void run() {
for(int i=0;i<20;i++){
synchronized(this){
if(this.ticket>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
" sell tickets= "+this.ticket--);
}
}
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"Thread A").start();
new Thread(mt,"Thread B").start();
new Thread(mt,"Thread C").start();;
}
}
2.同步方法:
class MyThread implements Runnable{
public int ticket=10;
@Override
public void run() {
for(int i=0;i<20;i++){
this.sale();
}
}
public synchronized void sale(){
if(this.ticket>0){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
" sell tickets= "+this.ticket--);
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"Thread A").start();
new Thread(mt,"Thread B").start();
new Thread(mt,"Thread C").start();;
}
}
同步虽然是数据安全操作,但效率特别的慢
线程的同步与死锁:
线程轮番抢占资源所带来的问题
多个线程卖票:
不同步的唯一好处是速度快,并发式多线程处理数据。
优先级越高越有可能先执行。(但仅仅是有可能)
方法:
public final void setPriority(int newPriority)
public final int getPriority()
优先级的设置的内容会通过Thread的几个常量来设置
最高:public static fianl int MAX_PRIORITY;(10)
中等:public static fianl int NORM_PRIORITY;(5)
最低:public static fianl int MIN
_PRIORITY;(1)
主方法是一个线程,那么主线程的优先级是一个中等优先级。
线程休眠
指的是让线程暂缓执行,等到了预计的时间在唤醒执行
方法:
public static void sleep(long millis)
throws InterruptedException
休眠时间使用毫秒作为单位
范例:
class MyThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<2000;i++){
System.out.println(Thread.currentThread().getName()+
" i = "+i);
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
通过代码会认为这三个代码是同时休眠的,但是所有代码是依次进入run()方法中的
真正进入方法的对象可能是多个,也可能是一个,所以所有的进入的代码的顺序可能有差异,延迟可能有差异,但是总体的执行是并发执行
lambda表达式
函数式编程:接口只能有一个方法
@FunctionInterface
接口定义加强
1.追加了普通方法 ,用default修饰
2.可以定义静态方法
流分为输入流和输出流:
流分为字节流和字符流:
字节流:(没有经过处理,是原生的操作)
inputStream:输入流
OutputStream:输出流:
字符流:(经过处理的)更适合处理中文
输入流:Reader
输出流:writer
不管使用的字符流还是字节流,其基本的操作流程基本是固定的。
1.要根据文件的路径创建File类对象。
2.根据字节流或者字符流的子类实例化父类对象。
3.进行数据的读取或者写入操作。
4.关闭流(IO属于资源处理,最后都要关闭close())
线程的命名和取得:
多线程的运行状态是不确定的,所以必须有一个明确标记来标记线程对象,用名称来描述
构造:(创建线程对象的时候设置好名字)
public Thread(Runnable target,
String name)
普通:设置该方法的名字
public final void setName(String name)
(final表示该方法不允许被子类覆写)
普通:得到该线程的名字
public final String getName()
但是如果要想取得线程的对象,在线程中:
*取得当前线程对象:
public static Thread currentThread()
范例:
class MyThread implements Runnable{
@Override
public void run() {
for(int x=0;x<10;x++){
System.out.println(Thread.currentThread().getName() +"x= "+x);
}
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt,"have name").start();
}
}
如果没有设置线程名字,系统会自动分配一个名字。如果自己设置线程名字,避免重复,且中间不要修改
范例:
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.run();
new Thread(mt).start();
}
}
以上说明主方法本身就是一个线程,所有的线程都是通过主线程创建并启动的。
每当我们使用了JAVA命令去解释程序的时候,都表示启动了一个新的JVM进程。而主方法只是这个进程上的一个线程而已。
通过Callable实现多线程
public interface Callable<V>{
public V call() throws Exception;
}
Runnable中的run()方法虽然也是线程的主方法,但并没有返回值
public FutureTask(Callable<V> callable)
class MyThread implements Callable<String>{
private int ticket=10,i=10;
@Override
public String call() throws Exception {
while(i-->0 && this.ticket>0){
System.out.println("Sell tickets:"+this.ticket--);
}
return "end";
}
}
public class Test {
public static void main(String args[]) throws InterruptedException, ExecutionException {
FutureTask<String> task=new FutureTask<String>(new MyThread());
new Thread(task).start();;
System.out.println(task.get());
}
}
这种形式主要是返回结果
线程的状态:
创建多线程后,调用start()之后,并不是立刻执行,而是进入到就绪状态,等待进行调度后执行,在资源调度后才执行多线程代码(run()中的代码),当你执行了一段时间后,需要让出资源,让其他线程继续执行,可能这时候的run()方法还没执行完。只执行了一半,那么就要让出资源,随后重新进入到就绪状态,重新等待分配资源,等待执行。当线程执行完毕后才会进入到终止状态。
Thread与Runnable的区别
public class Thread
extends Object
implements Runnable=》原来Thread类是Runnable接口的子类
Thread处理上使用的就是代理设计模式
Runnable实现的多线程的程序类可以更好的描述数据共享的概念
没有共享:
class MyThread extends Thread{
private int ticket=10,i=10;
public void run(){
while(i-->0 && this.ticket>0){
System.out.println("Sell tickets:"+this.ticket--);
}
}
}
public class Test {
public static void main(String args[]) {
new MyThread().start();
new MyThread().start();
new MyThread().start();
}
}
共享:
class MyThread extends Thread{
private int ticket=10,i=10;
public void run(){
while(i-->0 && this.ticket>0){
System.out.println("Sell tickets:"+this.ticket--);
}
}
}
public class Test {
public static void main(String args[]) {
MyThread ma=new MyThread();
new Thread(ma).start();
new Thread(ma).start();
new Thread(ma).start();
}
}
但结构不好
使用Runnable:
class MyThread implements Runnable{
private int ticket=10,i=10;
public void run(){
while(i-->0 && this.ticket>0){
System.out.println("Sell tickets:"+this.ticket--);
}
}
}
public class Test {
public static void main(String args[]) {
MyThread ma=new MyThread();
new Thread(ma).start();
new Thread(ma).start();
new Thread(ma).start();
}
}
如果一个类直接继承了Thread类将会造成单继承的局限
Runnable接口
public interface Runnable{
public void run();
}
}
Thread 构造方法
public Thread(Runnable target){}
多线程的启动永远都是Thread类的start()方法
对Runnable接口对象可以采用匿名对象,匿名内部类和Lambda函数表达式来定义
匿名内部类:
public class Test {
public static void main(String args[]) {
new Thread(new Runnable(){
public void run() {
System.out.println("Hello world");
}
}).start();
}
}
使用Lambda函数表达式:
public class Test {
public static void main(String args[]) {
new Thread(()->System.out.println("Hello world")).start();
}
}