简体   繁体   中英

Unintentional thread synchronization when writing to file

If I have a tread that counts to 1000 and prints out the result like so:

public class MyRunnable implements Runnable{
    @Override
    public  void run() {
        for (int i=0;i<1000;i++){
            System.out.println(i+" ");
        }
    }
}

And in main I do something like:

new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();

the results get jumbled up, since I'm not synchronizing.

But, if my thread looks like:

public class MyRunnable implements Runnable{
    Writer w;
    MyRunnable(Writer w){
        this.w=w;
    }

    @Override
    public  void run() {
        for (int i=0;i<1000;i++){
            try{
                w.write(String.valueOf(i));
                w.write (" ") ;
            }//&catch the exception
        }
    }
}

and my in main I have this this:

  try (Writer writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("Thread.txt"), "utf-8"))) {
       Thread t1 =new Thread(new MyRunnable(writer));
       Thread t2 =new Thread(new MyRunnable(writer));
       t1.start(); 
       t2.start();
       t1.join();
       t2.join();
   }    //catch the exception,etc.

The results look normal: the threads somehow got synchronized. I imagine it's because I pass writer as a parameter, but could someone explain it better? And, out of curiosity, is there any way around it?

EDIT: My apologies, it seems i hurried too much. I tried to simplify MyThread and removed too much code. but i just realized that the situation i described only happens if i try to open and read a file in run() method. So run actually looks like this:

public  void run() {
    try {
                Scanner scanner = new Scanner(f); //f is new File (filename) 
                while (scanner.hasNext())
                {
                    String str = scanner.next();
                    if (str.equals("word")) //code counts "word" appearance
                        count++;
                }
                scanner.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } 
             for (int i=0;i<1000;i++){
                try{
                    w.write(String.valueOf(i));
                    w.write (" ") ;
                }//&catch the exception
            } //continue by writing the count

I suppose this means the problem is actually in reading the file?

Writerwrite(String)方法( BufferedWriter从中扩展)是同步的。

This one will produce output in a non-synchronized manner. It is similar to yours, so I think there is something you are omitting.

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 */
public class ThreadTest {
    final static int N = 1000;

    static Runnable countDown(Writer writer){
        return ()->{
            for(int i = 0; i<N; i++){
                try{
                    writer.write(String.format("%d\t", i));
                } catch(Exception exc){

                }
            }

            try {
                writer.write("\n");
            } catch (IOException e) {
                e.printStackTrace();
            }
        };
    }

    public static void main(String[] args){
        try(
            Writer writer = Files.newBufferedWriter(Paths.get("test.txt"), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)
        ){
            Thread a = new Thread(countDown(writer));
            Thread b = new Thread(countDown(writer));
            a.start();
            b.start();
            a.join();
            b.join();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

Then the output becomes:

0   0   1   1   2   2   3   3   4   4   5   6   5   6   7   7   8   8   9   10  9   10  11  11  12  13  12  13  14  14  15  15  16  16  17  17  18  18  19  19  20  20  21  21  22  22  23  23  24  24  25  25  26  26  27  27  28  28  29  29  30  30  31  32  31  33  32  34  33  35  34  36  37  35  38  36  39  37  40  38  41  39  42  40  43  41  42  44  43  45  44  46  45  47  46  48  47  49  50  48  49  51  50  52  53  51  54  52  55  56  53  57  54  58  55  59  56  60  57  61  58  62  59  63  60  64  61  62  65  63  66  64  67  65  68  66  69  67  70  68  71  69  72  70  73  71  74  72  75  73  76  74  77  75  78  76  77  79  78  80  79  81  80  82  81  83  84  82  85  83  86  84  87  85  88  86  89  87  90  88  91  89  92  90  93  91  94  92  95  93  96  97  94  98  95  99  96  100 97  101 98  102 99  103 100 104 101 105 102 106 103 107 104 108 105 109 106 110 107 111 108 112 109 113 110 114 111 115 112 116 113 117 114 118 115 119 116 120 117 121 118 122 119 123 120 124 121 125 122 126 123 127 124 128 125 129 126 130 127 131 128 132 129 133 130 134 131 135 132 136 133 137 134 138 135 139 136 140 137 141 138 142 139 143 140 144 141 145 142 146 143 147 144 148 145 149 146 150 147 151 148 152 149 153 150 154 151 155 152 156 153 157 154 158 155 159 156 160 157 158 161 162 159 163 160 164 161 165 162 166 163 167 164 168 165 169 166 170 167 171 168 172 169 173 170 174 171 175 172 176 173 177 174 178 175 179 176 180 177 181 178 182 179 183 180 184 181 185 182 186 183 187 184 188 185 189 186 190 187 191 188 192 189 193 190 191 194 192 195 193 196 194 197 195 198 196 199 197 200 198 201 199 202 203 200 204 201 205 202 206 203 207 204 208 209 205 210 206 211 207 212 213 208 214 209 215 210 216 211 217 212 218 213 219 214 220 215 221 216 222 217 223 218 224 219 225 220 226 221 227 222 228 223 229 224 230 225 231 226 232 227 233 234 228 235 236 229 237 230 238 231 239 232 233 240 234 241 235 242 236 243 237 244 238 245 239 246 247 240 241 248 242 249 243 250 244 251 245 252 253 246 247 254 248 255 249 256 250 257 258 251 259 252 253 260 261 254 262 255 256 257 263 258 264 259 265 260 266 261 267 262 268 263 269 264 270 265 271 266 272 267 273 268 274 269 275 270 276 271 277 272 278 273 279 274 280 275 281 276 282 277 283 278 284 279 285 280 286 281 287 282 288 283 289 284 290 285 291 286 292 287 293 288 294 289 295 290 296 291 297 292 298 293 299 294 300 295 301 296 302 297 303 298 304 299 305 300 306 301 307 302 308 303 309 304 310 305 311 306 312 307 313 308 314 309 315 310 316 311 312 317 313 318 314 319 315 320 316 321 317 318 322 323 319 324 320 325 321 326 322 327 323 328 324 329 325 330 326 331 327 332 328 333 329 334 330 335 331 336 332 337 333 338 334 339 335 340 336 341 337 342 338 343 339 344 340 345 341 346 342 347 343 348 344 349 345 350 346 351 347 352 348 353 349 354 350 355 351 352 356 353 357 354 358 355 359 356 360 357 361 358 362 359 363 364 360 365 361 366 362 363 367 364 368 365 369 366 370 367 371 368 372 369 373 370 374 371 375 372 376 373 377 374 378 375 379 376 380 377 381 378 382 379 383 380 384 381 385 382 386 383 387 388 384 389 385 390 386 391 392 387 393 388 394 395 389 396 390 397 398 399 400 391 401 392 402 403 393 404 394 405 406 395 407 408 396 409 397 410 411 398 412 399 413 414 400 415 401 416 417 402 418 403 419 420 404 421 405 422 423 406 424 407 425 426 408 427 409 428 410 429 430 411 431 432 412 433 413 434 414 435 415 436 416 437 417 438 418 439 419 440 420 441 421 442 422 443 423 444 424 445 425 446 426 447 427 448 428 449 429 450 430 451 431 452 432 453 433 454 434 455 435 456 436 457 437 458 438 459 439 460 440 461 441 462 442 463 443 464 444 465 445 466 446 467 447 468 448 469 449 470 450 471 451 472 452 473 453 474 454 475 455 476 456 477 457 478 458 479 480 459 481 482 460 483 484 461 485 486 462 487 463 488 489 464 490 491 465 492 466 493 494 467 495 496 468 497 469 498 499 470 500 501 471 502 472 503 504 473 505 474 506 507 475 508 476 509 510 477 511 478 512 513 479 514 480 515 516 481 517 482 518 519 483 520 484 521 522 523 485 524 486 525 526 487 527 488 528 529 489 530 531 490 532 491 533 492 534 535 493 536 537 494 538 495 539 540 496 541 497 542 543 498 544 499 545 546 500 547 548 501 549 502 550 551 503 552 504 553 554 505 555 506 556 557 507 558 508 559 560 509 561 562 510 563 511 564 565 512 566 513 567 568 514 569 515 570 516 571 572 517 573 518 574 519 575 576 520 577 521 578 579 522 580 581 523 582 524 583 525 584 585 526 586 527 587 588 528 589 529 590 591 530 592 593 531 594 532 595 596 533 597 534 598 599 535 600 536 601 602 537 603 538 604 605 539 606 540 607 541 608 609 542 610 543 611 612 544 613 614 545 615 546 616 617 547 618 548 619 620 549 621 550 622 623 551 624 552 625 626 553 627 554 628 629 555 630 631 556 632 557 633 634 558 635 636 559 637 560 638 639 561 640 641 562 642 563 643 644 564 645 565 646 647 566 648 567 649 650 568 651 652 569 653 654 570 655 571 656 657 572 658 659 573 660 574 661 662 575 663 664 576 665 577 666 667 578 668 579 669 670 580 671 672 581 673 582 674 675 583 676 584 677 678 585 679 680 586 681 682 587 683 684 588 685 589 686 590 687 591 592 688 593 594 689 595 690 596 691 597 692 598 693 599 694 600 695 696 601 697 602 698 603 699 604 700 605 701 606 702 607 703 608 704 609 705 610 706 611 707 612 708 613 709 710 614 711 615 712 616 713 617 714 618 715 619 716 620 717 621 718 622 719 720 623 721 722 624 723 625 724 725 626 726 627 727 728 628 729 629 730 731 630 732 631 733 734 632 735 633 736 737 634 738 635 739 740 636 741 637 742 743 638 744 639 745 746 640 747 641 748 749 642 750 643 751 752 644 753 645 754 755 646 756 647 757 758 648 759 649 760 761 650 762 763 651 764 765 652 766 653 767 768 654 769 655 770 771 656 772 657 773 774 658 775 659 776 777 660 778 661 779 780 662 781 663 782 783 664 784 665 785 786 666 787 788 667 789 668 790 669 791 792 670 793 671 794 795 672 796 673 797 798 674 799 800 675 801 676 802 677 803 804 678 805 806 679 807 808 680 809 681 810 811 682 812 683 813 814 684 815 685 816 817 686 818 687 819 820 688 821 689 822 823 690 824 691 825 826 692 827 693 828 829 694 830 695 831 832 696 833 697 834 835 698 836 699 837 838 700 839 701 840 841 702 842 703 843 704 844 705 845 706 846 707 847 708 848 709 849 710 850 711 851 712 852 853 713 854 714 855 715 856 716 857 717 858 718 859 719 860 720 861 721 862 722 863 723 864 724 865 725 866 726 867 727 868 728 869 729 870 730 871 731 872 732 873 733 874 734 875 735 876 736 877 737 878 738 879 739 880 740 881 741 882 742 883 743 884 744 885 745 886 746 887 747 748 888 889 749 890 891 750 892 893 751 894 895 752 896 753 897 898 754 899 900 755 901 902 756 903 757 904 905 758 906 907 759 908 760 909 910 761 911 912 762 913 914 763 915 916 764 917 765 918 919 766 920 921 767 922 923 768 924 769 925 926 770 927 928 771 929 772 930 931 773 932 774 933 934 775 935 936 776 937 777 938 939 778 940 779 941 780 942 943 781 944 945 782 946 783 947 948 784 949 785 950 951 786 952 787 953 954 788 955 789 956 957 790 958 791 959 960 792 961 793 962 794 963 964 795 965 796 966 797 967 798 968 969 799 970 971 800 972 801 973 974 802 975 976 803 977 804 978 979 805 980 981 806 982 807 983 984 808 809 985 986 810 987 811 988 812 813 989 990 814 991 815 992 816 993 817 818 994 819 995 996 820 997 821 998 822 823 999 
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 

Which, as you can see ends up jumbled.

In the case of your Scanner, since you are making two Scanner for the same file on windows you are essentially synchronizing on the file. eg. The read/write condition ends up looking like this:

try{
    synchronized(f){
        Scanner s = new Scanner(f);
        System.out.println("starting");
        while(s.hasNext()){
            System.out.println(s.next().length());
        }
        System.out.println("finished");
        s.close();
    }
}catch(Exception e){e.printStackTrace();}

The result of this is that, one thread reads the file, finishes and starts counting, at that point the other thread starts reading the file. Reading the file takes much longer than counting down.

It's not clear what you want exactly. But if you just want t1 and t2 to mix up their numbers you should make sure they start exactly at the same time. An easy way to do that is to use a CountdownLatch that you store in your threads like this:

public class MyRunnable implements Runnable{
        Writer w;
        CountDownLatch countDownLatch;
        MyRunnable(Writer w, CountDownLatch countDownLatch){
            this.w=w;
            this.countDownLatch=countDownLatch;
        }

        @Override
        public  void run() {
            countDownLatch.await();
            for (int i=0;i<1000;i++){
                try{
                    w.write(String.valueOf(i));
                    w.write (" ") ;
                }//&catch the exception
            }
        }
}

And that you create before the thread and launch when they are created:

try (Writer writer = new BufferedWriter(new OutputStreamWriter(
        new FileOutputStream("Thread.txt"), "utf-8"))) {
    CountDownLatch countDownLatch = new CountDownLatch(1);
    Thread t1 =new Thread(new MyRunnable(writer, countDownLatch));
    Thread t2 =new Thread(new MyRunnable(writer), countDownLatch);
    t1.start();
    t2.start();
    countDownLatch.countDown(); //Start the threads
    t1.join();
    t2.join();
}    //catch the exception,etc.

This will make sure that the time taken for the thread creation doesn't influence your test and that both threads actually start at the same time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM